☰ INDEX
Abortion
Abrasions
Adipocere, Mummification & Embalming
Age Estimation By X-Ray Examination
Age
Agriculture Poisons
Alcohol
Algor Mortis
Asphyxiants
Barbiturates & Chloral Hydrate
Blood & Seminal Stains
Burns
Cardiac Poisons & Aconite
Classification Of Sexual Offences & Rape
Classification of Postmortem Changes
Consent & Euthanasia
Contusions
Corrosives
Counter Coup Lesions & Concussion
Courts Of Law
Death & It's Types
Decomposition
Defenses Against Negligence
Definitions & Inquest
Definitions
Deliriant Poisons
Drowning
Drug Dependence & Abuse
Electrical Injuries
Evidence
Explosion Injuries
Eye Changes After Death
Finger Printing
Food Poisoning
Forensic Psychiatry
General Principles of Toxicology
Hair & Other Methods of Identification
Hanging
Heavy Metal Poisons
Important Concepts Related to Medical Negligence
Impotence & Sterility
Infamous Conduct
Injuries Due To Cold & Heat
Intracranical Haemorrhages
Introduction To Ballistics & Firearms
Investigations Of Firearms
Lacerations & Incised Wounds
Lie Detectors
Ligature Strangulation & Throttling
Lightning Injuries & Scalds
Live Birth
Medico - Legal Autopsy
Medico-Legal Aspects of Injuries
Medico-Legal Importance of Age Groups
Muscular Charges
Opium
Other Forms Of Asphyxia
Phosphorous
Post Mortem Hypostasis
Professional Negligence
Professional Secrecy & Privileged Communication
Race
Rifled Gun & It's Injuries
Sex
Shotgun & It's injuries
Skull Fractures
Snakes
Spinal Poisons
Stab Wounds
Stature
Summons
Syndromes-Battered Baby, Munchausen & SID's
Time Since Death & Legal Aspects
Traffic Accident Injuries
Unnatural Sexual Offences & Perversions
Vegetable Poisons
Vertebral Column, Heart & Abdomen
Virginity & Pregnancy
Witness
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "With the consent of the pregnant lady, abortion is carried out using electricity of 1000 volts. Unexpectedly, the pregnant woman dies. Which section deals with this?", "options": [{"label": "A", "text": "Sec 314 IPC", "correct": true}, {"label": "B", "text": "Sec 315 IPC", "correct": false}, {"label": "C", "text": "Sec 316 IPC", "correct": false}, {"label": "D", "text": "Sec 317 IPC", "correct": false}], "correct_answer": "A. Sec 314 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec 314 IPC Sec 314 IPC - Death caused by an act done with intent to cause miscarriage. Whoever, with intent to cause the miscarriage of a woman with child, does any act which causes the death of such woman, shall be punished with imprisonment of either description for a term which may extend to ten years, and shall also be liable to fine; And if the act is done without the consent of the woman, the accused shall be punished either with 1[imprisonment for life] or with the punishment above mentioned. It is not essential to this offence that the offender should know that the act is likely to cause death.</p>\n<p><strong>Random:</strong></p><p>Explanation for Incorrect Options:- Option: B. Sec 315 IPC - Act done with the intent to prevent a child from being born alive or to cause it to die after birth. Whoever, before the birth of any child does any act with the intention of thereby preventing that child from being born alive or causing it to die after its birth, and does by such act prevent that child from being born alive, or causes it to die after its birth, shall, if such an act is not caused in good faith for the purpose of saving the life of the mother, be punished with imprisonment of either description for a term which may extend to ten years, or with fine, or with both. Option: C. Sec 316 IPC Causing the death of a quick unborn child by act amounting to culpable homicide.-Whoever does any act under such circumstances, that if he thereby caused death he would be guilty of culpable homicide, and does by such act cause the death of a quick unborn child, shall be punished with imprisonment of either description for a term which may extend to ten years, and shall also be liable to fine. Option: D. Sec 317 IPC. Exposure and abandonment of a child under twelve years, by a parent or person taking care of it.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Borax is given in high doses and is repeated every 2 hours to a pregnant woman. As a consequence, she gets aborted due to increased menstrual blood flow. Such substances are called:", "options": [{"label": "A", "text": "Emmenagogue", "correct": true}, {"label": "B", "text": "Ecobolics", "correct": false}, {"label": "C", "text": "Abortifacient drugs", "correct": false}, {"label": "D", "text": "Both A & B", "correct": false}], "correct_answer": "A. Emmenagogue", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Emmenagogue Emmenagogues: They produce or increase the menstrual flow. They act as abortifacients when given in large and repeated doses. The chief of these is savin, borax, apiol, rue, and Oestrogens, sanguinarin, Senecio, caulophyllin, hellebore.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B & D. Ecobolics: They increase uterine contraction but do not relax or dilate the cervical canal and external os, which is necessary to expel the Foetus. Ergot is most commonly used and has a uterine action which increases as pregnancy advances, but its toxic circulatory side effects result in arterial spasms and gangrene of the extremities. It frequently fails during the earlier months of pregnancy. Option: C. Abortifacient Drugs: Every common drug has been used at some time in an attempt to produce criminal abortion. They either produce a congestion of the uterine mucosa and then uterine bleeding, followed by contraction of the uterine muscle and expulsion of the Foetus, or they cause the uterine contraction by stimulating the myometrium directly. There is no drug which when taken by the mouth causes abortion without endangering the life of the woman.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A middle-aged woman with profuse vaginal bleeding is brought to the hospital. Products of conception are seen coming out. She gave a history of her husband and in-laws trying to abort by inserting some kind of stick into her genitalia. In this context, how would you differentiate criminal abortion from natural abortion?", "options": [{"label": "A", "text": "Erosion and inflammation of the vagina", "correct": true}, {"label": "B", "text": "Predisposing disease may be present", "correct": false}, {"label": "C", "text": "Marks of violence absent on abdomen", "correct": false}, {"label": "D", "text": "Injury to the genital organ is absent", "correct": false}], "correct_answer": "A. Erosion and inflammation of the vagina", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Erosion and inflammation of the vagina In the case of criminal abortion, erosion and inflammation of the vagina and cervix due to the local application of irritant substances may be present. Difference between natural & criminal abortion: Points Natural abortion Criminal abortion 1.Cause 1. Natural 1.Induced 2.Infection 2.Rare 2.Frequent 3.Marks of violence on abdomen 3.Not present 3. May be present 4.Injuries in genital organs 4.Absent 4.Present 5.Toxic effects of drugs 5.Absent 5.Present in vagina, cervix, GIT, UT 6. Foreign bodies in genital tract 6.Absent 6. May be present 7.Foetus 7.Wounds are absent. 7.Wounds may be present.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A woman claimed that she had been assaulted while pregnant, and as a result of violence, she had aborted. The products of alleged abortion were sent, which on examination was found to be the 'foetus' of a DOG. The forelegs and tail had been clipped off and the remains bottled. This is:", "options": [{"label": "A", "text": "Fabricated abortion", "correct": true}, {"label": "B", "text": "Criminal abortion", "correct": false}, {"label": "C", "text": "Unsafe abortion", "correct": false}, {"label": "D", "text": "Therapeutic abortion", "correct": false}], "correct_answer": "A. Fabricated abortion", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Fabricated abortion Rarely, when a woman is assaulted. she may try to exaggerate the offence by alleging that it caused her to abort. She may acquire a human Foetus, or an animal Foetus to support the charge. CASE: A woman claimed that she had been assaulted while pregnant, and as a result of violence, she had aborted. The products of the alleged abortion were sent, which on examination was found to be the 'foetus' of a dog. The forelegs and tail had been clipped off and the remains bottled.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Option: Option: B. Criminal Abortion: A criminal abortion is the induced destruction and expulsion of the Foetus from the womb of the mother unlawfully, i.e., when there is no therapeutic indication for the operation. It is resorted to mostly by widows and unmarried women. It is usually carried out before the third month. A case of criminal abortion is investigated only when the woman dies, and rarely when someone gives the information to the police Option: C. Unsafe abortion means abortion is not provided through approved facilities, and/or persons Option: D. Justifiable or Therapeutic Abortion: Abortion is justifiable only when it is done in good faith to save the life of the woman if it is materially endangered by the continuance of the pregnancy</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 14 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Abrasion injuries give important medicolegal answers about the manner of injuries. Choose the incorrect statement about abrasion.", "options": [{"label": "A", "text": "In throttling, crescentic abrasions due to fingernails are found on the neck", "correct": false}, {"label": "B", "text": "In smothering, abrasions may be seen around the mouth and nose", "correct": false}, {"label": "C", "text": "In sexual assaults. Abrasions may be found on the breasts, genitals, inner side of the thighs, and around the anus", "correct": false}, {"label": "D", "text": "Abrasions on the face of the victim indicates a struggle", "correct": true}], "correct_answer": "D. Abrasions on the face of the victim indicates a struggle", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Abrasions on the face of the victim indicates a struggle Abrasions on the face of the assailant indicate a struggle Medicolegal Importance of Abrasion They give an idea about the site of impact and the direction of the force. They may be the only external signs of a serious internal injury. Patterned abrasions help connect the wound with the object which produced them. The age of the injury can be determined, which helps to corroborate the alleged time of the In open wounds, dirt, dust, grease, or sand are usually present, which may connect the injuries to the scene of the crime. Character and manner of injury may be known from its distribution. Abrasions on the face of the assailant indicate a struggle. Abrasions on the victim may show whether the fingernails of the assailant were long, irregular, or even broken</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. In throttling, crescentic abrasions due to fingernails are found on the neck. Option: B In smothering, abrasions may be seen around the mouth and nose. Option: C In sexual assaults. Abrasions may be found on the breasts, genitals, inner side of the thighs, and around the anus.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Identify the type of abrasion in this Illustration", "options": [{"label": "A", "text": "Grazed abrasion", "correct": false}, {"label": "B", "text": "Linear abrasion", "correct": false}, {"label": "C", "text": "Imprint abrasion", "correct": true}, {"label": "D", "text": "Ectopic bruise", "correct": false}], "correct_answer": "C. Imprint abrasion", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892561878-QTDF031002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Imprint abrasion Impact Abrasions (contact or imprint abrasions): They are caused by impact with a rough object when the force is applied at or near a right angle to the skin surface. The abrasion is slightly depressed below the surface unless there is bulging due to underlying contusion or local edema. If the impact is forcible, the dermis is damaged with an underlying bruise. When a person is knocked down by a motor car, the pattern of the radiator grille, a headlamp rim, or the tread of the tire may be seen on the skin, which may contain road dirt, paint flakes, grease, etc. Impact by a solid object may produce abrasion at the periphery where the skin is forced downwards. If a person strikes a flat and relatively smooth surface, an abrasion can be produced which shows little or no linear markings, as in traffic accidents.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Grazes (sliding, scraping, or grinding abrasion):- are the most common type. They occur when there is movement between the skin and some rough surface in contact with it. They show uneven, longitudinal parallel lines (grooves or furrows) with the epithelium heaped up at the ends of these lines, which indicate the direction in which the force was applied. The furrow may be broad at one end, and narrow in the opposite direction. Usually, the skin is uniformly denuded at the start or may be serrated. The epidermis is scraped away, destroyed, or detached. A glancing kick with a boot also produces a graze. These abrasions are commonly seen in road accidents. It is a scraping injury over a large area. \"Friction burn\" (scuff or brush abrasion) is an extensive, superficial, reddened excoriated area without serous ooze or bleeding and with little or no linear mark. It may occur due to tangential contact with a smooth surface or when the skin is covered by clothing. Brush bums and friction bums are seen in motorcyclists, persons ejected from vehicles, pedestrians, and cyclists thrown forward after the primary impact from a motor vehicle. If a victim is struck with a glancing blow with a rough object, such as a stone or a stick, a brush bum will be caused. Option: B A scratch (linear abrasion) is an abrasion with length but no significant width, or a very superficial incision, depending on the agent Option: D Ectopic bruising, or Percolated or Migratory contusion:- The bruise which appears in some other site apart from the area of impact.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was involved in a road traffic accident. He received multiple injuries which were luckily non-fatal. The commonest type of abrasion seen in road traffic accidents is:", "options": [{"label": "A", "text": "Scratch abrasions", "correct": false}, {"label": "B", "text": "Graze abrasions", "correct": true}, {"label": "C", "text": "Pressure abrasions", "correct": false}, {"label": "D", "text": "Imprint abrasions", "correct": false}], "correct_answer": "B. Graze abrasions", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Graze abrasions Grazes (sliding, scraping, or grinding abrasion): They are the most common type. They occur when there is movement between the skin and some rough surface in contact with it. They show uneven, longitudinal parallel lines (grooves or furrows) with the epithelium heaped up at the ends of these lines, which indicate the direction in which the force was applied. They are seen in motorcyclists, persons ejected from vehicles, pedestrians, and cyclists thrown forward after the primary impact from a motor vehicle. If a victim is struck with a glancing blow with a rough object, such as a stone or a stick, a brush bum will be caused.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: A scratch (linear abrasion) is an abrasion with length but no significant width, or a very superficial incision, depending on the agent. Option C: Pressure Abrasions /crushing abrasion/friction They are caused by the crushing of the superficial layers of the epidermis and are associated with a bruise of the surrounding area. If the movement of the instrument is around 90° to the skin, a pressure type of abrasion occurs. In this type, the movement is slight and largely directed inwards. The ligature mark in cases of hanging and strangulation and the teeth bite marks are examples. Option D: Impact Abrasions (contact or imprint abrasions): They are caused by impact with a rough object when the force is applied at or near a right angle to the skin surface. The abrasion is slightly depressed below the surface unless there is bulging due to underlying contusion or local edema If the impact is forcible, the dermis is damaged with an underlying bruise. When a person is knocked down by a motor car, the pattern of the radiator grille, a headlamp rim, or the tread of the tire may be seen on the skin, which may contain road dirt, paint flakes, grease, etc. Impact by a solid object may produce abrasion at the periphery where the skin is forced downwards. If a person strikes a flat and relatively smooth surface, an abrasion can be produced which shows little or no linear markings, as in traffic accidents.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A cycle rickshaw runs over the legs of a 10 yrs old child while playing on the road. There is a tire mark that can be seen on the child’s legs. This is:", "options": [{"label": "A", "text": "Patterned bruise", "correct": false}, {"label": "B", "text": "Patterned abrasion", "correct": true}, {"label": "C", "text": "Imprint abrasion", "correct": false}, {"label": "D", "text": "Stretched laceration", "correct": false}], "correct_answer": "B. Patterned abrasion", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Patterned abrasion Impact abrasions and pressure abrasions reproduce the pattern of the object causing it and are called patterned abrasions. Patterned injury is any injury that suggests an inflicting instrument or unique means of its causation. Patterned abrasions are produced when the force is applied at a right angle to the surface of the If the skin is struck with a weapon having a patterned surface, or the body falls against a patterned surface, the abrasion of the epidermis is caused by the ridges of the object, if it has a profile of varying height. The skin may be compressed into the cavities of the pattern with capillary damage leading to an intradermal bruise, e.g., when a motor tire passes over the skin. Other examples of patterned abrasion are imprints of bicycle chains, weaves of coarse fabrics, the spiral of electric wires, ropes, serrated knives, etc. Multi-thronged whip, such as a cat-o-nine-tails, leaves a series of linear abrasions or superficial tears. Usually, the pattern and shape are non-specific.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Patterned Bruising: A patterned contusion is one in which the size and shape mirror a portion of the object which caused it. With heavier impacts or objects, the tissues beneath the impacting objects are crushed, and the contusion pattern is solid rather than outlined Option C: Impact Abrasions (contact or imprint abrasions): They are caused by impact with a rough object when the force is applied at or near a right angle to the skin surface. The abrasion is slightly depressed below the surface unless there is bulging due to underlying contusion or local edema. If the impact is forcible, the dermis is damaged with an underlying bruise. When a person is knocked down by a motor car, the pattern of the radiator grille, a headlamp rim, or the tread of the tire may be seen on the skin, which may contain road dirt, paint flakes, grease, etc. Impact by a solid object may produce abrasion at the periphery where the skin is forced downwards. If a person strikes a flat and relatively smooth surface, an abrasion can be produced which shows little or no linear markings, as in traffic accidents. Option D: Stretch Lacerations: Overstretching of the skin, if it is fixed, will cause lacerations. There is localized pressure with a pull which increases until tearing occurs and produces a flap of skin, which is peeled off the underlying bone or deep fascia. This is seen in the running over by a motor vehicle, and the flap may indicate the direction of the vehicle.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A natural death case was kept in storage for identification formalities. After two days after the autopsy, there were multiple abrasion-like lesions on the body. Antemortem abrasions can be confused with:", "options": [{"label": "A", "text": "Eczema", "correct": false}, {"label": "B", "text": "Ant bite marks", "correct": true}, {"label": "C", "text": "Chemical burns", "correct": false}, {"label": "D", "text": "Joule burns", "correct": false}], "correct_answer": "B. Ant bite marks", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ant bite marks Erosions of the Skin Produced by Ants : Ants produce brown erosions with minute irregular margins of the superficial layers of the skin. They are most commonly found at mucocutaneous junctions, about the eyelids, nostrils, mouth, ears, knuckles, axillae, groins, and genitalia. They are also seen in the moist folds of the skin. Sometimes they are localized and may simulate antemortem abrasions. Examination by hand lens shows multiple crescent-shaped, sand-like bite marks. Each one is separated by normal skin. Vital reaction Scab dries shrinks and falls off, leaving depigmented area underneath, which gets gradually pigmented</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options - A, C , & D: Eczema, Chemical burns, and Joule burns don't mimic antemortem abrasions.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Marks shown in the Illustration are seen in", "options": [{"label": "A", "text": "Contusion", "correct": false}, {"label": "B", "text": "Pressure abrasion", "correct": true}, {"label": "C", "text": "Graze abrasion", "correct": false}, {"label": "D", "text": "Linear abrasion", "correct": false}], "correct_answer": "B. Pressure abrasion", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892562596-QTDF031006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pressure abrasion Pressure Abrasions (crushing or friction abrasions): They are caused by the crushing of the superficial layers of the epidermis and are associated with a bruise of the surrounding area. If the movement of the instrument is around 90° to the skin, a pressure type of abrasion occurs. In this type, the movement is slight and largely directed inwards. The ligature mark in cases of hanging and strangulation and the teeth bite marks are the examples.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: A contusion is an effusion Of blood into the tissues, due to the rupture of blood vessels (veins, venules, and arterioles, caused by blunt trauma, such as a fist, stone, stick, bar, whip, hammer, Option C: Graze abrasions Grazes (sliding, scraping, or grinding abrasion They occur when there is movement between the skin and some rough surface in contact with it. They show uneven, longitudinal parallel lines (grooves or furrows They are seen in motorcyclists, persons ejected from vehicles, pedestrians, and cyclists thrown forward after the primary impact from a motor vehicle. If a victim is struck a glancing blow with a rough object, such as a stone or a stick, a brush bum will be caused. Option D: A scratch (linear abrasion) is an abrasion with length but no significant width, or a very superficial incision, depending on the agent</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A robber tried to smother the owner when he woke up and confronted the robber. Which of the following is a positive finding in the case of smothering death?", "options": [{"label": "A", "text": "Fracture of the hyoid bone", "correct": false}, {"label": "B", "text": "Fracture of thyroid bone", "correct": false}, {"label": "C", "text": "Crescentic nail marks on the neck", "correct": false}, {"label": "D", "text": "Abrasions & bruise on the inner side of the lips", "correct": true}], "correct_answer": "D. Abrasions & bruise on the inner side of the lips", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Abrasions & bruise on the inner side of the lips The lips, gums, and tongue may show bruising or laceration. Slight bruising may be found in the mouth and nose, which should be confirmed by microscopy in case of smothering death.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A & B : Fractures of the hyoid and thyroid are seen in strangulation and also in hanging. It is not seen in traumatic asphyxia usually. Option C: Crescentic nail marks on the neck are seen in cases of manual strangulation and not in traumatic asphyxia.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An auto ran over a child. There is a mark of the tire tracks over the body, it is an example of:", "options": [{"label": "A", "text": "Patterned bruise", "correct": false}, {"label": "B", "text": "Pressure abrasion", "correct": false}, {"label": "C", "text": "Ectopic bruise", "correct": false}, {"label": "D", "text": "Imprint abrasion", "correct": true}], "correct_answer": "D. Imprint abrasion", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Imprint abrasion Impact Abrasions (contact or imprint abrasions): They are caused by impact with a rough object when the force is applied at or near a right angle to the skin surface. The abrasion is slightly depressed below the surface unless there is bulging due to underlying contusion or local edema. If the impact is forcible, the dermis is damaged with an underlying bruise. When a person is knocked down by a motor car, the pattern of the radiator grille, a headlamp rim, or the tread of the tire may be seen on the skin, which may contain road dirt, paint flakes, grease, etc. Impact by a solid object may produce abrasion at the periphery where the skin is forced downwards. If a person strikes a flat and relatively smooth surface, an abrasion can be produced which shows little or no linear markings, as in traffic accidents.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Patterned Bruising: A patterned contusion is one in which the size and shape mirror a portion of the object which caused it. With heavier impacts or objects, the tissues beneath the impacting objects are crushed, and the contusion pattern is solid rather than outlined. Option B: Pressure Abrasions /crushing abrasion/friction abrasion They are caused by the crushing of the superficial layers of the epidermis and are associated with a bruise of the surrounding area. If the movement of the instrument is around 90° to the skin, a pressure type of abrasion occurs. In this type, the movement is slight and largely directed inwards. The ligature mark in cases of hanging and strangulation and the teeth bite marks are examples. Option C: Ectopic bruising, or Percolated or Migratory contusion:- The bruise appears in some other sites apart from the area of impact.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A head injury patient showed a contusion over his mastoid. Battle’s sign is an example of:", "options": [{"label": "A", "text": "Patterned bruise", "correct": false}, {"label": "B", "text": "Deep bruise", "correct": false}, {"label": "C", "text": "Ectopic bruise", "correct": true}, {"label": "D", "text": "Delayed bruise", "correct": false}], "correct_answer": "C. Ectopic bruise", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ectopic bruise Battle's sign is an example of an ectopic bruise. Examples of ectopic bruises are - In fracture of the jaw, a bruise may appear in the neck. In a fracture of the pelvis, a bruise may appear on the thigh. In a fracture of the femur, a bruise may appear on the outer side of the lower part of the thigh. A blow to the upper thigh may appear as a bruise above the knee. A kick on the calf of the leg may appear as a bruise around the ankle. The site of bruising does not always indicate the site of the violence.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Patterned Bruising: A patterned contusion is one in which the size and shape mirror a portion of the object which caused it. With heavier impacts or objects, the tissues beneath the impacting objects are crushed, and the contusion pattern is solid rather than outlined. Option D: Delayed Bruising : A superficial bruise appears immediately as a dark-red swelling. A deep bruise may take several hours, or one or two days to appear and deeper extravasation of blood may never appear Option B: Deep contusions are seen during the autopsy, as the blood is drained from blood vessels and also due to postmortem autolytic changes. A contusion of the brain may initiate enough swelling with gradual accumulation of acid by-products of metabolism, with further swelling and impairment of function, confusion, coma, and death.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In firearm entry wound, arrangement of abrasion collar, dirt collar, and tattooing from inside to outside:", "options": [{"label": "A", "text": "Dirt collar, abrasion collar, tattooing", "correct": true}, {"label": "B", "text": "Abrasion collar, dirt collar, tattooing", "correct": false}, {"label": "C", "text": "Tattooing, dirt collar, abrasion collar", "correct": false}, {"label": "D", "text": "Dirt collar, tattooing, abrasion collar", "correct": false}], "correct_answer": "A. Dirt collar, abrasion collar, tattooing", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Dirt collar, abrasion collar, tattooing Dirt collar, tattooing, abrasion collar Grease or dirt ring may be present inner to or interwoven in the substance of the abrasion collar, which may be demonstrable on micro-chemical or other tests in the laboratory. Burning, singeing, blackening, and tattooing may be seen at appropriate distances</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B, C, and D: The order in other Options is not correct.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The followings are features of adipocere:", "options": [{"label": "A", "text": "Fresh adipocere resembles rancid butter", "correct": false}, {"label": "B", "text": "Old adipocere is dry, hard and brittle", "correct": false}, {"label": "C", "text": "Adipocere is odourless", "correct": true}, {"label": "D", "text": "Adipocere is inflammable", "correct": false}], "correct_answer": "C. Adipocere is odourless", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Adipocere is odourless Adipocere has a distinct offensive or sweetish smell, but during the early stages of its production, a penetrating ammoniacal odour is noticed. The smell remains in the clothing of those handling such bodies for several days. One's olfactory sense rapidly becomes accustomed to the smell of adipocere, and one cannot smell it after about two minutes of The sense of smell rapidly returns after a few minutes in the open air.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & B . Fresh adipocere is soft, moist, whitish and translucent, but old samples are dry, hard, cracked, yellowish and brittle. It shows fragments of fibrous tissues and muscle in the fracture. Option: D . It is inflammable and burns with a faint-yellow flame. It floats in water and dissolves in alcohol and ether.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body was recovered from the waterside with a waxy appearance. Adipocere is most commonly seen:", "options": [{"label": "A", "text": "Hot and dry condition", "correct": false}, {"label": "B", "text": "Damp and warm environment", "correct": true}, {"label": "C", "text": "Damp and cold environment", "correct": false}, {"label": "D", "text": "No specific climate is required", "correct": false}], "correct_answer": "B. Damp and warm environment", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Damp and warm environment Adipocere is delayed by cold and hastened by heat. A warm, moist, anaerobic environment favours adipocere formation. It is more frequently seen in females, well-nourished mature newborn children, the obese and corpses that have been submerged in water for a long period. It is also seen in buried bodies. Foetuses under seven months do not show this change. The bodies enclosed in a water-tight coffin for many years may be converted to adipocere even in the absence of external water.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Adipocere is delayed by cold and dry conditions. It requires warm and damp conditions. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A waxy body was recovered and submitted for autopsy. Importance of Adipocere:", "options": [{"label": "A", "text": "Preserves the injured site", "correct": false}, {"label": "B", "text": "Preserves identification of face", "correct": false}, {"label": "C", "text": "Helps to estimate time since death", "correct": false}, {"label": "D", "text": "All the above", "correct": true}], "correct_answer": "D. All the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All the above Medicolegal Importance of adipocere formation</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & B. When the process involves the face, the features are well preserved, which helps to establish the identity. The cause of death can be determined because injuries are recognised. Option: C . The time since death can be estimated.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following is the best embalming technique?", "options": [{"label": "A", "text": "Continuous injection & drainage", "correct": false}, {"label": "B", "text": "Discontinuous injection & drainage", "correct": true}, {"label": "C", "text": "Continuous injection & disrupted drainage", "correct": false}, {"label": "D", "text": "Alternate injection & drainage", "correct": false}], "correct_answer": "B. Discontinuous injection & drainage", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Discontinuous injection & drainage DISCONTINUOUS INJECTION AND DRAINAGE: This consists of repeated arterial injection of small quantities at two-hour The total quantity of injection fluid is more than the ordinary injection done at a time. The injection is continued three or four times. The venous drain tube which is kept closed is opened a little before and kept open a little after starting another dose of injection. This is the best method</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D . Since the best technique for embalming is discontinuous injection and drainage, other methods are insignificant in this question. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Embalming before medico-legal autopsy may be punished under the section:", "options": [{"label": "A", "text": "174 IPC", "correct": false}, {"label": "B", "text": "201 IPC", "correct": true}, {"label": "C", "text": "294 IPC", "correct": false}, {"label": "D", "text": "297 IPC", "correct": false}], "correct_answer": "B. 201 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>201 IPC S. 201, I.P.C.: Causing the disappearance of evidence of the offence, or giving false information to screen offenders (imprisonment up to ten years). Embalming alters the appearance of the body, tissues and organs, making it difficult to interpret any injury or disease. Embalming completely destroys cyanide, alcohol and many other substances. Determining the presence of many alkaloids and organic poisons becomes very difficult. The fixation process makes it difficult to extract drugs. Blood grouping cannot be made out. Thrombi and emboli will be dislocated and washed away.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: 174 IPC- Non-attendance in obedience to an order from the court of law intentionally, i.e. summons (imprisonment up to six months or fine up to one thousand rupees, or both. Option C: 294 IPC - Whoever to the annoyance of others (a) does any obscene act in any public place or (b) sings, recites or utters any obscene song, Ballard or words, in or near any public place shall be punished with imprisonment up to 3 months, or with fine or with both. Option D: 297 IPC - Necrophilia and necrophagia are punishable under S. 297, I.P.C. with imprisonment up to one year and/or a</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "True statement regarding mummification among the following is/are:", "options": [{"label": "A", "text": "Time since death can be estimated", "correct": false}, {"label": "B", "text": "Facial features are preserved", "correct": false}, {"label": "C", "text": "Skin is shrunken, dry and brown", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above Mummification begins in the exposed parts of the body like the face, hands and feet and then extends to the entire body including the internal organs. The skin may be shrunken and contracted, dry, brittle, leathery and rusty-brown to black, stretched tightly across anatomical prominences, such as the cheekbones, chin, coastal margins and hips, adheres closely to the bones, and often covered with fungal growths. As the skin contracts, some of the fat cells in the subcutaneous tissues are broken, and the liquid oil is forced into the dermis which becomes translucent. The entire body loses weight up to 60 to 70% and becomes thin, stiff and brittle. In mummified bodies, arms are often abducted in the shoulder joints, and flexed in elbow joints and hands are clenched into fists in most cases. This flexion is often seen in lower limbs also. This is due to the shrinkage of muscles and tendons. Mummification may be partial in some cases, with only limbs or head or trunk being affected. Mummified tissues are dry, leathery and brown. The internal organs become shrunken; hard, dark brown and black and become a single mass. Later, due to putrefaction and maggot activity, they may disappear. If a mummified body is not protected, it will break into fragments gradually, becomes powdery and disintegrates, but if protected, it may be preserved for years. Mummified bodies may be attacked by insects especially moths and larvae of various flies which destroy the body. A mummified body is practically odourless.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following poisoning may favour mummification?", "options": [{"label": "A", "text": "Arsenic", "correct": true}, {"label": "B", "text": "Lead", "correct": false}, {"label": "C", "text": "Phosphorous", "correct": false}, {"label": "D", "text": "Mercury", "correct": false}], "correct_answer": "A. Arsenic", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Arsenic Marked dehydration before death favours the development of mummification. Mummification occurs in bodies buried in shallow graves in dry sandy soils, where evaporation of body fluids is very rapid due to the hot Dry winds in summer. Chronic arsenic or antimony poisoning is said to favour the process.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C & D. Lead, Phosphorous and Mercury do not favour mummification. Some may even delay the process. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "What is the odour of the mummified body?", "options": [{"label": "A", "text": "Odorless", "correct": true}, {"label": "B", "text": "Pungent", "correct": false}, {"label": "C", "text": "Putrid", "correct": false}, {"label": "D", "text": "Offensive", "correct": false}], "correct_answer": "A. Odorless", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Odorless Features of mummification:- Begins in the exposed parts of the body like the face, hands and feet and then extends to the entire body including the internal organs. The skin may be shrunken and contracted, dry, brittle, leathery and rusty-brown to black, stretched tightly across anatomical prominences, such as the cheekbones, chin, coastal margins and hips, adheres closely to the bones, and often covered with fungal growths. As the skin contracts, some of the fat cells in the subcutaneous tissues are broken, and the liquid oil is forced into the dermis which becomes translucent. The entire body loses weight up to 60 to 70%, becoming thin, stiff and brittle. In mummified bodies, arms are often abducted in the shoulder joints, and flexed in elbow joints and hands are clenched into fists in most cases. This flexion is often seen in lower limbs also. This is due to the shrinkage of muscles and tendons. Mummification may be partial in some cases, with only limbs or head or trunk being affected. Mummified tissues are dry, leathery and brown. The internal organs become shrunken; hard, dark brown and black and become a single mass. Later, due to putrefaction and maggot activity, they may disappear. If a mummified body is not protected, it will break into fragments gradually, becomes powdery and disintegrates, but if protected, it may be preserved for years. Mummified bodies may be attacked by insects especially moths and larvae of various flies which destroy the body. A mummified body is practically odourless.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C & D. Since the mummified body is practically odourless, other Options are irrelevant to this question. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A girl child is born to a couple who were expecting a baby boy. They were already parents to 4 healthy-living girl children. The couple didn't want to keep the 5th newborn baby girl. So, they kept the baby inside a cupboard where the temperature is warm and dry. These factors are favourable for", "options": [{"label": "A", "text": "Mummification", "correct": true}, {"label": "B", "text": "Saponification", "correct": false}, {"label": "C", "text": "Adipocere formation", "correct": false}, {"label": "D", "text": "autolysis", "correct": false}], "correct_answer": "A. Mummification", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mummification Mummification of newborn children may occur if they are left in a trunk, or a kitchen cupboard, where the atmosphere is warm and dry. Marked dehydration before death favours the development of mummification. Mummification occurs in bodies buried in shallow graves in dry sandy soils, where evaporation of body fluids is very rapid due to the hot dry winds in summer. Chronic arsenic or antimony poisoning is said to favour the process MUMMIFICATION;- It is a modification of putrefaction. Dehydration or drying and shrivelling of the cadaver occurs from the evaporation of water, but the natural appearances of the body and general facial features are preserved</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C: Adipocere (cire=wax)/Saponification is a modification of putrefaction. In this, the fatty tissues of the body change into a substance known as adipocere. It is seen most commonly in bodies immersed in water or a damp, warm environment. Option: D. Autolysis: Autolysis is the self-digestion of tissues. Soon after the death, cell membranes become permeable and break down, with the release of cytoplasm-containing Autodigestion by acid gastric juice is a common finding in newborns and infants and is seen as softening and rupturing of the stomach and lower oesophagus. In adults, such digestion may start before death in cases of intracranial lesions. The earliest external sign is a whitish, cloudy appearance in the cornea.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Mummified body smells like?", "options": [{"label": "A", "text": "Odourless", "correct": true}, {"label": "B", "text": "Fishy", "correct": false}, {"label": "C", "text": "Bitter almond", "correct": false}, {"label": "D", "text": "Sweetish", "correct": false}], "correct_answer": "A. Odourless", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Odourless It is a modification of putrefaction. Dehydration or drying and shrivelling of the cadaver occurs from the evaporation of water, but the natural appearances of the body and general facial features are preserved. It begins in the exposed parts of the body like the face, hands and feet and then extends to the entire body including the internal organs. The skin may be shrunken and contracted, dry, brittle, leathery and rusty-brown to black, stretched tightly across anatomical prominences, such as the cheekbones, chin, coastal margins and hips, adheres closely to the bones, and often covered with fungal growths. A mummified body is practically odourless.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C & D. Since the mummified body is odourless, other Options of smells are insignificant to this question. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The process in which tissues of the body change into a waxy substance, which is seen most commonly in bodies immersed in water or a damp, warm environment is called?", "options": [{"label": "A", "text": "Embalming", "correct": false}, {"label": "B", "text": "Mummification", "correct": false}, {"label": "C", "text": "Putrefaction", "correct": false}, {"label": "D", "text": "Adipocere", "correct": true}], "correct_answer": "D. Adipocere", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Adipocere Adipocere (cire=wax) is a modification of putrefaction. In this, the fatty tissues of the body change into a substance known as adipocere. It is seen most commonly in bodies immersed in water or a damp, warm environment.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. Embalming Embalming is the treatment of the dead body with antiseptics and preservatives to prevent putrefaction and preserve the body. By this process proteins are coagulated, tissues are fixed, organs are bleached and hardened and blood is converted into a brownish mass. Option B. Mummification It is a modification of putrefaction. Dehydration or drying and shrivelling of the cadaver occurs from the evaporation of water, but the natural appearances of the body and general facial features are preserved. Option C. Putrefaction The disintegration of body tissues after death is known as decomposition. The terms decomposition and putrefaction are used as synonyms. Putrefaction usually follows the disappearance of rigor mortis. During the hot season, it may commence before rigor mortis has completely disappeared from the lower extremities.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Adipocere has a distinct offensive or sweetish smell, but during the early stages of its production, a penetrating odour is noticed. What odour is noticed?", "options": [{"label": "A", "text": "Sweet smelling", "correct": false}, {"label": "B", "text": "Ammoniacal odour", "correct": true}, {"label": "C", "text": "Sulfur oxides", "correct": false}, {"label": "D", "text": "Formaldehyde", "correct": false}], "correct_answer": "B. Ammoniacal odour", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ammoniacal odour Adipocere has a distinct offensive or sweetish smell, but during the early stages of its production, a penetrating ammoniacal odour is noticed. The smell remains in the clothing of those handling such bodies for several days. One's olfactory sense rapidly becomes accustomed to the smell of adipocere, and one cannot smell it after about two minutes of The sense of smell rapidly returns after a few minutes in the open air.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Sweet smelling Not correct Option: C. sulfur oxides Not correct Option: D. Formaldehyde Not correct</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Assertion: The rate of adipocere formation is extremely variable. Reason: In temperate countries, the shortest time for its formation is about three weeks in summer, when it occurs to a certain extent. Stiffening, hardening and swelling of the fat occur over a period of months. In most cases, the change is partial and irregular, but rarely the whole body may be affected.", "options": [{"label": "A", "text": "Both assertion and reason are correct and the reason is the correct explanation of assertion.", "correct": true}, {"label": "B", "text": "Both assertion and reason are correct BUT reason is NOT the correct explanation of assertion.", "correct": false}, {"label": "C", "text": "Statement 1 is right BUT 2 is wrong", "correct": false}, {"label": "D", "text": "Statement 2 is right but 1 is wrong", "correct": false}], "correct_answer": "A. Both assertion and reason are correct and the reason is the correct explanation of assertion.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both assertion and reason are correct and the reason is the correct explanation of assertion. Time Required for Adipocere Formation: The rate of adipocere formation is extremely variable. In temperate countries, the shortest time for its formation is about three weeks in summer, when it occurs to a certain extent. Stiffening, hardening and swelling of the fat occur over a period of months. In most cases, the change is partial and irregular, but rarely the whole body may be affected. Complete conversion in an adult limb requires at least three to six months. In India, it has been observed to begin within 4 to 5 days. Adipocere may persist for years or decades. Medicolegal Importance: When the process involves the face, the features are well preserved, which helps to establish the identity. The cause of death can be determined because injuries are recognised. The time since death can be estimated.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "What stage of decomposition is depicted in the following image", "options": [{"label": "A", "text": "Adipocere", "correct": true}, {"label": "B", "text": "Putrefaction", "correct": false}, {"label": "C", "text": "Mummification", "correct": false}, {"label": "D", "text": "Algor mortis", "correct": false}], "correct_answer": "A. Adipocere", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893129499-QTDF050016IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Adipocere The above image depicts the stage of adipocere formation. Adipocere (cire=wax) is a modification of putrefaction. In this, the fatty tissues of the body change into a substance known as adipocere. It is seen most commonly in bodies immersed in water or damp, warm environments.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Putrefaction The disintegration of body tissues after death is known as decomposition. The terms decomposition and putrefaction are used as synonyms. Putrefaction usually follows the disappearance of rigor mortis. During the hot season, it may commence before rigor mortis has completely disappeared from the lower extremities. Option: C. Mummification It is a modification of putrefaction. Dehydration or drying and shrivelling of the cadaver occurs from the evaporation of water, but the natural appearances of the body and general facial features are preserved. Option : D Algor mortis It’s the process of cooling down a dead Heat is generated by the residual metabolic process (glycogenolysis) of dying tissues and by the metabolic activity of intestinal bacteria, due to which body temperature does not fall for some time. With the start of cooling, a temperature gradient develops from the surface to the core of any part of the body. The exchange of heat between the core and the surface of the body occurs only by conduction.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The process of dehydration or drying and shrivelling of the cadaver from the evaporation of water, where the natural appearances of the body and general facial features are preserved is called?", "options": [{"label": "A", "text": "Adipocere", "correct": false}, {"label": "B", "text": "Mummification", "correct": true}, {"label": "C", "text": "Putrefaction", "correct": false}, {"label": "D", "text": "Rigor mortis", "correct": false}], "correct_answer": "B. Mummification", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mummification It is a modification of putrefaction. Dehydration or drying and shrivelling of the cadaver occurs from the evaporation of water, but the natural appearances of the body and general facial features are preserved.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Adipocere Adipocere (cire=wax) is a modification of putrefaction. In this, the fatty tissues of the body change into a substance known as adipocere. It is seen most commonly in bodies immersed in water or a damp, warm environment. Option: C. Putrefaction It is the last stage of decomposition, the destruction of tissues/body. The disintegration of body tissues after death is known as decomposition. The terms decomposition and putrefaction are used as synonyms. Option: D. Rigor mortis Rigor mortis (death stiffening; cadaveric rigidity) is a state of stiffening of muscles, sometimes with slight shortening of the fibres. Individual cell death takes place in this stage.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 25 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A child was brought to orthopaedics for pain in the right hand. The parents told that he twisted his hand while playing with a ball. The X-ray is given below. What is the estimated age of the child?", "options": [{"label": "A", "text": "10 Years", "correct": true}, {"label": "B", "text": "6 Years", "correct": false}, {"label": "C", "text": "2 Years", "correct": false}, {"label": "D", "text": "18 Years", "correct": false}], "correct_answer": "A. 10 Years", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891555106-QTDF002001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>10 Years In the given X-ray image, all the carpal bones have appeared. The ossification centre of pisiformis has appeared which appears at around 10-12 yrs.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: D. Also the radius and ulnar bone ossification centre has not fused. Hence the age cannot be 18 years. Option: B & C. Age cannot be 6 years or 2 years as in, because all the carpel bones will have not appeared as shown in this image.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person under the legal guardianship of the court is now set free as he has attained the age of taking his own responsibility. Which of the following given below X-ray of the wrist depicts the age of this person?", "options": [{"label": "A", "text": "A", "correct": false}, {"label": "B", "text": "B", "correct": false}, {"label": "C", "text": "C", "correct": true}, {"label": "D", "text": "None of the above.", "correct": false}], "correct_answer": "C. C", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891555129-QTDF002002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>C In the given question, the person has attained the age of 18 years and now he is free from the legal guardianship of the court. From all the above X-rays, option C is the correct answer. In the given image, all carpal bone ossification centres have appeared. Also, the ossification centre of the radius and ulna are also fused which occurs around the age of 18.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. The radius and ulnar bone ossification centre have not fused. Hence it cannot be of 18 yr old. As all carpal bones are present along with pisiformis, the estimated age will be 10-12 years. Option: B. In image B, only two carpal bones are visible, so the estimated age for this will be, under 1 year of age.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During anthropological excavation, you find some remains of the bone which you have sent for the age estimation. One of the bones found is given below. In the given bone, when does the ossification of cristae scapulae occur by-", "options": [{"label": "A", "text": "30 Years", "correct": false}, {"label": "B", "text": "40 Years", "correct": false}, {"label": "C", "text": "50 Years", "correct": true}, {"label": "D", "text": "35 Years", "correct": false}], "correct_answer": "C. 50 Years", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891555274-QTDF002003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>50 Years In the given question, the bone given in the image is the scapula. The ossification of cristae scapulae occurs by the age of 50 years.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. & D. Between 30 to 35 years, lipping starts on the ventral margin of the glenoid cavity. Option: B. By 35 to 40 years, irregular lipping occurs around the clavicular facet and inferior surface of the acromion process. By 45 years, localised bony atrophy can be seen.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "On the accident spot, you find a man lying in a car against the steering wheel with his chest lying on it. His autopsy was to be done. In his previous chest x-ray which was done 10 days back, you can see his sternal body ossified and the xiphoid process ossified, but the manubrium is not fused with the body. What will be the age of this patient?", "options": [{"label": "A", "text": "25 Years", "correct": false}, {"label": "B", "text": "10 Years", "correct": false}, {"label": "C", "text": "30 Years", "correct": false}, {"label": "D", "text": "50 Years", "correct": true}], "correct_answer": "D. 50 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>50 Years In the given question, according to the ossification pattern of the sternum, - sternal body gets fused in three different parts between 14-20 years. Xiphoid process fuses with the body at around 40 years. And the manubrium fuses with the body at around 60 years. Hence as in this patient manubrium is not fused, so his age is less than 60 years but more than 40 years at the xiphoid process is fused. So the answer will be 50 years according to the given options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A female who lives by the roadside was in extreme pain in the hip region while walking. She was brought to the hospital by people from an NGO who help these people. Her X-ray of the hip is given below. What will be the minimum age of this female?", "options": [{"label": "A", "text": "15 Years", "correct": false}, {"label": "B", "text": "18 Years", "correct": false}, {"label": "C", "text": "20 Years", "correct": true}, {"label": "D", "text": "25 Years", "correct": false}], "correct_answer": "C. 20 Years", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891555949-QTDF002005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>20 Years In the given question, according to the X-ray image given of the pelvis of the female for evaluation of hip pain, we could easily make out that the various ossification centres have appeared and fused. Head of the femur, Greater trochanter, lesser trochanter- all fuses at around 17-18 years. In this patient, all are fused. Also the last ossification centre to fuse here is ischial tuberosity, which fuses at 20-22 years of age. It is fused in this patient. Hence the minimum age of this patient should be 20 years. So the answer is C. 20 years.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You are the head of the forensic medicine department at AIIMS. Today, you will be taking the class on ‘age estimation’ for 2nd year MBBS students. You prepare the following slide in which you put two different X-rays and ask your student to estimate the age at the end of the class. Which of the following is a correct match of the age with the given X-ray? In image A, the age of the person will be>12 years, as all the carpal bone ossification centres have In image B the age of the person will be a minimum of 9 years, as the centre of ulnar olecranon has Minimum age of the image A person will be between 10-12 years, and that of image B will be 16 years. In image A, the centre of ossification for the lower end of the radius has not appeared. Select the correct answer from the given below code:-", "options": [{"label": "A", "text": "1,2,3", "correct": false}, {"label": "B", "text": "1,3,4", "correct": false}, {"label": "C", "text": "1,3", "correct": true}, {"label": "D", "text": "2,4", "correct": false}], "correct_answer": "C. 1,3", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891556398-QTDF002006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,3 In the given two images, image A shows an X-ray of the elbow- All the carpal bones have appeared hence age will be >12 years of age. (Statement 1) the centres of ossification have appeared (statement 4 is wrong) for the lower end of the radius, but have not fused hence the age will be less than 18 years. Image B depicts – an X-Ray of the elbow- in which all the centres of ossification have fused, hence the minimum age will be 16 years. (Statement 3) Statement 2 is wrong, as the ossification centre of the ulna has appeared and fused also. Hence the correct statement is 1,3.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A student was studying age estimation from skull suture fusion. Identify the suture in the Image given below:", "options": [{"label": "A", "text": "Coronal suture", "correct": false}, {"label": "B", "text": "Sagittal suture", "correct": false}, {"label": "C", "text": "Lambdoid suture", "correct": true}, {"label": "D", "text": "Metopic suture", "correct": false}], "correct_answer": "C. Lambdoid suture", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891788428-QTDF010001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lambdoid suture</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "For stature determination from bones, the bones are needed to measure on an osteometric board. Which of the following is an osteometric board:", "options": [{"label": "A", "text": "Image A", "correct": false}, {"label": "B", "text": "Image B", "correct": true}, {"label": "C", "text": "Image C", "correct": false}, {"label": "D", "text": "Image D", "correct": false}], "correct_answer": "B. Image B", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891788563-QTDF010002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Image B OSTEOMETRIC BOARD: This has a rectangular base with a ruler fixed along one of its long sides. An upright is set at one end of the board, and a second one slides along the board. The bone is placed with one of its ends against the fixed upright, and the movable upright is brought up to the other end of the bone. The distance between the uprights is then shown on the ruler. Hepburn osteometric board modified by Trevor is commonly used. If an osteometric board is unavailable, the bones should be measured on a flat bench with the maximum lengths taken between two vertical, parallel panels placed in contact with the bone ends. If the bones are covered with articular cartilage, subtract for radius and humerus 3 mm. each, the tibia 5 mm. and the femur 7 mm before applying the formulae for stature estimation. Weight-bearing long bones are used for applying these formulae. Femur and tibia give more accurate results than the humerus or radius. The average stature obtained from measuring more than one long bone gives a more precise result than when calculated for a single bone. Right-side bones usually are measured in a dry state without cartilage. The results could be more accurate, and the error may be up to 2.5 cm. Measurements of the femur, tibia, humerus, and radius are helpful.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. foot measuring board/shoe measuring board Option: C. Skinfold measuring calipers Option: D. Infantometer</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Forensic odontology is an important method of age estimation. Consider which of the following statement is true about the marked tooth:", "options": [{"label": "A", "text": "Marked tooth erupts earlier in the lower jaw", "correct": false}, {"label": "B", "text": "Marked tooth erupts earlier in the upper jaw", "correct": true}, {"label": "C", "text": "Marked tooth erupts at the same time in both upper and lower jaw", "correct": false}, {"label": "D", "text": "Marked tooth appears at birth", "correct": false}], "correct_answer": "B. Marked tooth erupts earlier in the upper jaw", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891788924-QTDF010003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Marked tooth erupts earlier in the upper jaw The marked tooth is a lateral incisor. It occurs earlier in the upper jaw. The eruption is defined as the only part of the crown of the tooth appearing level with the surface of the alveolar bone In both deciduous and permanent teeth; dentition occurs earlier in the lower jaw except for the lateral incisors, which erupt earlier in the upper jaw. The lower permanent incisors, premolars, and molars erupt about six months to a year earlier than the corresponding teeth in the upper jaw. Wisdom tooth first erupts in the lower and on the left side and then on the right side</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The stack method is used to determine the age of infants using teeth. In the stack’s method, what are two teeth parameters considered in estimating age?", "options": [{"label": "A", "text": "Weight of teeth", "correct": false}, {"label": "B", "text": "Height of teeth", "correct": false}, {"label": "C", "text": "Both A and B", "correct": true}, {"label": "D", "text": "Width of teeth", "correct": false}], "correct_answer": "C. Both A and B", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both A and B STACK'S METHOD: Stack evolved a method to know the age of infants from the weight and height of the erupting teeth of a child. This method can be used on deciduous and permanent teeth during their erupting phase.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "While examining the teeth, the senior consultant advised the junior doctor to look for space behind the second molar and determine whether it was hard. Spacing of jaw is to make room for eruption of:", "options": [{"label": "A", "text": "Incisor", "correct": false}, {"label": "B", "text": "Canine", "correct": false}, {"label": "C", "text": "Premolar", "correct": false}, {"label": "D", "text": "3rd molar", "correct": true}], "correct_answer": "D. 3rd molar", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>3rd molar Spacing of Jaw: - After the eruption of the second molars, the ramus of the jaw grows behind when the body of the jaw increases in length to make room for the eruption of the third molar teeth. Hence, while examining the teeth, the space behind the second permanent molar is to be felt; if the area is present, it is to be seen if it is hard to handle.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "It is well-known that with age, temporary teeth fall, and permanent teeth erupt. These permanent teeth are either successional or superadded. Which of the following teeth is not a permanent successional tooth?", "options": [{"label": "A", "text": "Central incisor", "correct": false}, {"label": "B", "text": "Lateral incisor", "correct": false}, {"label": "C", "text": "First premolar", "correct": false}, {"label": "D", "text": "First molar", "correct": true}], "correct_answer": "D. First molar", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>First molar Successional permanent teeth are those which erupt in place of deciduous teeth. Permanent premolars erupt in place of deciduous molars. Successional teeth are ten in each jaw. Permanent molars are superadded teeth.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Teeth eruption occurs around a definite age group. However, the third molar is very variable in eruption. If a third molar erupts it indicates that the individual is above:", "options": [{"label": "A", "text": "12 Years", "correct": false}, {"label": "B", "text": "14 Years", "correct": false}, {"label": "C", "text": "16 Years", "correct": false}, {"label": "D", "text": "17 Years", "correct": true}], "correct_answer": "D. 17 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>17 Years If third molars fully erupt, an individual is above 17. In some persons, due to inadequate jaw space, the third molars never erupt into the oral cavity, particularly the mandibular third molars. Such trapped teeth are known as impacted teeth. All the teeth can be visualized by a single X-ray, by dental panoramic Tomograph (orthopantomogram).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The lower jaw is an important part of the skull and useful in identification, especially the teeth it contains. The bone itself gives a clue about the age of the person. In which stage of life the angle of the mandible is an almost right angle?", "options": [{"label": "A", "text": "Infancy", "correct": false}, {"label": "B", "text": "Adult", "correct": true}, {"label": "C", "text": "Old age", "correct": false}, {"label": "D", "text": "Never right angle", "correct": false}], "correct_answer": "B. Adult", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Adult Difference between mandible in infancy, adult life and old age. Trait Infancy Adult Old age (1) Body Shallow. Thick and long. Shallow. (2) Ramus Short and oblique; forms obtuse angle with body. Less obtuse angle (almost straight) with the body. Obtuse angle with the body, about 140°. (3) Mental foramen Opens near the lower margin. Opens midway between upper and lower margins. Opens near the alveolar margin. (4) Condyloid process At a lower level than coronoid process. Elongated and projects above coronoid process. At a lower level than coronoid process.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Some teeth were recovered from exhumation with other parts of the skeleton. The attending doctor decided to use Gustafson’s method for age estimation with the teeth. The most reliable criteria in Gustafson’s method of age determination from teeth are:", "options": [{"label": "A", "text": "Attrition", "correct": false}, {"label": "B", "text": "Periodontosis", "correct": false}, {"label": "C", "text": "Root resorption", "correct": false}, {"label": "D", "text": "Root transparency", "correct": true}], "correct_answer": "D. Root transparency", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Root transparency Transparency of root occurs from below upwards in the lower jaw and from above downwards in the upper jaw. It is the most reliable of all criteria. Other criteria of Gustafson’s method are secondary dentine deposition and cementum apposition.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Attrition: Due to wear and tear from chewing, the occlusal (upper) surface of99+ the teeth is gradually destroyed, first involving the enamel, then dentin, and at last, the pulp is exposed in old age. It depends on the practical use of teeth and also on the hardness of the enamel. Option: B. Periodontosis: Regression of the gums and periodontal tissues surrounding the teeth takes place in advancing age, gradually exposing the necks and the adjacent part of roots. The teeth become loose and fall off. Poor oral hygiene increases periodontosis. There may be deposition of hardened debris which occurs gradually over a long period. Secondary dentin: It may develop from the walls within the pulp cavity and decrease the size of the cavity. First,, it is deposited at the pulp chamber, gradually extending downwards to the apex, and may fill the pulp cavity. This is partly due to aging and partly due to pathological conditions like caries and periodontosis. Cementum apposition: The cementum increases in thickness mainly due to changes in the tooth position, especially near the end of the root. Secondary cementum is slowly and continuously deposited throughout life and forms incremental lines. Incremental lines appear as cross-striations on the enamel of teeth due to cementum apposition and are thought to represent daily growth increments. They can be seen in the histological section. The age can be calculated by counting the number of lines from the neonatal line onward. This is mainly applicable to infants. Option: C: Root resorption: It involves both cementum and dentin, which show characteristically sharp grooves. Absorption of the root starts first at the apex and extends upwards. It usually occurs at late age. It may be due to a pathological processes.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Gustafson’s method uses six criteria on teeth to determine the age of an adult. Some of these criteria need the removal of teeth and examination under microscope while other criteria can be studied on gross. All of the following criteria of Gustafson’s method show increase with age except:", "options": [{"label": "A", "text": "Cementum apposition", "correct": false}, {"label": "B", "text": "Periodontosis", "correct": true}, {"label": "C", "text": "Secondary dentine", "correct": false}, {"label": "D", "text": "Root transparency", "correct": false}], "correct_answer": "B. Periodontosis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Periodontosis With increasing age there is regression of root (root resorption), periodontal tissues ( paradontosis) and mastication area of teeth ( attrirtion). Other parameters increase with age Periodontosis and attrition can be examined both microscopically as well as macroscopically. Secondary dentin, root resorption root transparency and cementum apposition can be examined only microscopically.(Other Options )</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Some joints of a child were radiographed to determine his age. Estimate the bone age from the X-ray wrist joint shown below:", "options": [{"label": "A", "text": "Less than 16 years", "correct": true}, {"label": "B", "text": "Between 20-22 years", "correct": false}, {"label": "C", "text": "Between 18-19 years", "correct": false}, {"label": "D", "text": "Less than 17.5 years", "correct": false}], "correct_answer": "A. Less than 16 years", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891790698-QTDF010011IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Less than 16 years Image shows X-ray photograph of the wrist and hand. All the carpal bones are seen. The lower epiphyses (head) of first metacarpal not united with the shaft. Age between 12 to 16 years.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "First set of milk teeth appear what age?", "options": [{"label": "A", "text": "3 months", "correct": false}, {"label": "B", "text": "6 months", "correct": true}, {"label": "C", "text": "9 months", "correct": false}, {"label": "D", "text": "12 months", "correct": false}], "correct_answer": "B. 6 months", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>6 months Temporary Teeth : Temporary, deciduous or milk teeth are 20 in number: 4 incisors, 2 canines, and 4 molars in each jaw and start to appear by 6 months. First temporary tooth to erupt is lower central incisor at the age of 6 months.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A teeth was recovered from exhumation. The consultant decided to apply Stack’s formula. Stack Formula is used to estimate age through dentition and is used for?", "options": [{"label": "A", "text": "Infants", "correct": true}, {"label": "B", "text": "Adults 25-50yrs", "correct": false}, {"label": "C", "text": "Adult >50yr", "correct": false}, {"label": "D", "text": "Elderly", "correct": false}], "correct_answer": "A. Infants", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Infants STACK'S METHOD: Stack evolved a method to know the age of infants from the weight and height of the erupting teeth of child. This method can be used on both deciduous and permanent teeth during their erupting phase.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Four carpal bones are present at what age?", "options": [{"label": "A", "text": "2 Years", "correct": false}, {"label": "B", "text": "4 Years", "correct": true}, {"label": "C", "text": "6 Years", "correct": false}, {"label": "D", "text": "8 Years", "correct": false}], "correct_answer": "B. 4 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>4 Years The ossification centres in carpal bones appear as follows: capitate 2 to 3 months, hamate first year; triquitrum 3, lunate 4, scaphoid and trapezoid 5, trapezium 6, pisiform 11 years. At the end of one year, two carpal bones are seen in X-ray of the wrist. Between 2 to 6 years, the number of carpal bones present on X-ray indicates the approximate age in years. Capitate: 1-3 months Hamate: 2-4 months Triquetral: 2- 3 years Lunate: 2- 4 years Scaphoid: 4-6 years Trapezium: 4-6 years Trapezoid: 4-6 years Pisiform: 8-12 years</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "What is the predicted bone age from the wrist radiograph given below", "options": [{"label": "A", "text": "3 months", "correct": true}, {"label": "B", "text": "1 year", "correct": false}, {"label": "C", "text": "3 years", "correct": false}, {"label": "D", "text": "Neonate", "correct": false}], "correct_answer": "A. 3 months", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891790703-QTDF010016IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>3 months At birth, there is no calcification in the carpal bones. Although there is great individual variability, approximate ossification times are as follows 1: Capitate: 1-3 months Hamate: 2-4 months Triquetrum: 2-3 years Lunate: 2-4 years Scaphoid: 4-6 years Trapezium: 4-6 years Trapezoid: 4-6 years Pisiform: 8-12 years</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 25 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A case of organophosphate poisoning was admitted to the emergency. Which of the following is more accurate in the diagnosis of organophosphate poisoning?", "options": [{"label": "A", "text": "RBC cholinesterase", "correct": true}, {"label": "B", "text": "Plasma cholinesterase", "correct": false}, {"label": "C", "text": "Both of the above are equally accurate", "correct": false}, {"label": "D", "text": "Serum Electrolyte levels", "correct": false}], "correct_answer": "A. RBC cholinesterase", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>RBC cholinesterase Five ml of heparinised blood should be collected for cholinesterase determination. Serum is separated, and both are refrigerated. Alternatively, samples can be frozen for cholinesterase. The average normal cholinesterase values are 77 to 142 in the red cells and 41 to 140 in the plasma. RBC cholinesterase level of less than 50% of normal indicates OP poisoning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Clinical features of organophosphorus poisoning include all of the following except", "options": [{"label": "A", "text": "Miosis", "correct": false}, {"label": "B", "text": "Dryness of mouth", "correct": true}, {"label": "C", "text": "Vomiting", "correct": false}, {"label": "D", "text": "Urinary incontinence", "correct": false}], "correct_answer": "B. Dryness of mouth", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Dryness of mouth A muscarine-like effect which potentiates postganglionic parasympathetic activity and affects pupils, bronchial mucous, salivary and sweat glands (stimulated), urinary bladder (contracted), cardiac sinus node (blocked'· Muscarinic receptors for acetylcholine are found primarily in the smooth muscles, heart and exocrine glands. Nicotine-like stimulation is followed by paralysis of postganglionic and somatic motor nerves, causing twitching of the eyelids, tongue and facial muscles, and neuromuscular block and paralysis. Nicotinic signs and symptoms result from the accumulation of acetylcholine at the endings of motor nerves to skeletal muscles and autonomic ganglia. Central nervous system stimulation followed by depression causes a headache, giddiness, restlessness, apprehension, tremors, ataxia, insomnia, coma and death.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The treatment of choice for organophosphorus poisoning is", "options": [{"label": "A", "text": "Atropine", "correct": true}, {"label": "B", "text": "Adrenaline", "correct": false}, {"label": "C", "text": "Neostigmine", "correct": false}, {"label": "D", "text": "Physostigmine", "correct": false}], "correct_answer": "A. Atropine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Atropine In case of OP poisoning, avoid physostigmine, edrophonium chloride and succinylcholine. Atropine sulphate arrests the muscarine effects of postganglionic parasympathetic (peripheral) activity (muscarinic receptor antagonist) and arrests CNS effects. Atropine should be continued until the tracheobronchial tree is cleared of the secretions and most secretions are dried, but not pupillary status.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The most specific laboratory test for organophosphorus poisoning is the estimation of", "options": [{"label": "A", "text": "Plasma cholinesterase level", "correct": false}, {"label": "B", "text": "Red cells cholinesterase level", "correct": true}, {"label": "C", "text": "Serum organophosphorus level", "correct": false}, {"label": "D", "text": "All have an equal value", "correct": false}], "correct_answer": "B. Red cells cholinesterase level", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Red cells cholinesterase level RBC cholinesterase is a more specific level of less than 50% of normal indicates poisoning. The plasma cholinesterase is more sensitive and will fall more rapidly than red cells. Thus, if there is a dissociation of the two, i.e. if the plasma is down and red cells relatively little changed, the amount of exposure is less.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A child accidentally drank mosquito repellant at home. The active compound in mosquito repellent ‘All Out’ is a:", "options": [{"label": "A", "text": "Organophosphorous compound", "correct": false}, {"label": "B", "text": "Organ chlorine compound", "correct": false}, {"label": "C", "text": "Carbamates", "correct": false}, {"label": "D", "text": "Pyrethrin compound", "correct": true}], "correct_answer": "D. Pyrethrin compound", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pyrethrin compound Pyrethrins are extracted from the chrysanthemum Pyrethroids are synthetic analogues. Toxicity is very low due to their rapid metabolism. They are used as insect repellents, insecticides and pesticides. They are available as sprays, dust, powders, mats and coils. Pyrethrum, allethrin, D-allethrin, permethrin, deltamethrin, decamethrin, cypermethrin, fenvalerate, and flavalinate are some</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A poisoning patient was admitted. The attending doctor diagnosed miosis. Miosis is not a feature of ________ poisoning:", "options": [{"label": "A", "text": "Barbiturate", "correct": false}, {"label": "B", "text": "Benzodiazepines", "correct": false}, {"label": "C", "text": "Phenol", "correct": false}, {"label": "D", "text": "Datura", "correct": true}], "correct_answer": "D. Datura", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Datura In Datura poisoning, the face becomes flushed, conjunctivae congested, and pupils widely dilated with loss of accommodation for near vision, developing into temporary blindness, photophobia and diplopia. Light reflex at first is sluggish and later absent.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A chronic multidrug abuser was admitted for rehabilitation. Carphologia is seen in", "options": [{"label": "A", "text": "Opiate toxicity", "correct": false}, {"label": "B", "text": "Datura poisoning", "correct": true}, {"label": "C", "text": "Lead overdose", "correct": false}, {"label": "D", "text": "Snake Bite", "correct": false}], "correct_answer": "B. Datura poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Datura poisoning Carphologia tries to pull imaginary threads from the tips of his fingers, threads imaginary needles seen in Datura poisoning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The product of cannabis obtained as latex from flowers is", "options": [{"label": "A", "text": "Majun", "correct": false}, {"label": "B", "text": "Bhang", "correct": false}, {"label": "C", "text": "Hashish", "correct": false}, {"label": "D", "text": "Ganja", "correct": true}], "correct_answer": "D. Ganja", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ganja It is prepared from the flower tops of the female plant. It has a rusty-green colour and a characteristic odour. It is mixed and smoked with tobacco in a pipe or hukka. It contains 15 to 25% of the active principle. Ganja (pot, grass, weed, maryjone,) also known as marihuana, is used for smoking in cigarettes containing 0.3 to 0.6 g. cannabis and are known as Reefer or Joint.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A small boy playing in a field consumes some poisonous material. He is brought to the hospital with a dry mouth, tachycardia, full urinary bladder, dilated and non-reacting pupils, with a flushed face. The most likely poison consumed is:", "options": [{"label": "A", "text": "Unripe poppy capsule", "correct": false}, {"label": "B", "text": "Flower top of cannabis", "correct": false}, {"label": "C", "text": "Dhatura", "correct": true}, {"label": "D", "text": "Oleander", "correct": false}], "correct_answer": "C. Dhatura", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Dhatura Signs and symptoms of Datura poisoning:- A bitter taste, dry mouth and throat, difficulty talking, dysphagia, burning pain in the stomach and vomiting are fusts The voice becomes hoarse. The face becomes flushed, conjunctivae are congested, and pupils widely dilated with loss of accommodation for near vision, developing into temporary blindness, photophobia and diplopia. Light reflex at first is sluggish and later absent. Urinary retention and inability to pass urine occur. The patient becomes confused, giddy, and staggers as if drunk.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Threading of imaginary needles or pulling of threads from tips of fingers is seen in case of poisoning by", "options": [{"label": "A", "text": "Barbiturate", "correct": false}, {"label": "B", "text": "Cocaine", "correct": false}, {"label": "C", "text": "Cannabis", "correct": false}, {"label": "D", "text": "Dhatura", "correct": true}], "correct_answer": "D. Dhatura", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Dhatura The patient of Datura poisoning may be silent. Still, usually, he is noisy, tries to run away from his bed, picks at the bedclothes (carphologia), and pulls imaginary threads from the tips of his fingers, threads imaginary needles.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Identify the plant as seen in the Illustration", "options": [{"label": "A", "text": "Datura", "correct": false}, {"label": "B", "text": "Cannabis", "correct": true}, {"label": "C", "text": "Poppy", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "B. Cannabis", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893645936-QTDF063011IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cannabis Cannabis is also known as Indian hemp. The plant grows all over India, but its cultivation is legally restricted. The female plant is taller, about 4 to 6 metres, and has darker and more luxuriant foliage than the male. The active principles are contained in its resin. The principal constituent of the resin is cannabinol, which has no action; cannabidiol is also inert, but on exposure to heat, it is partly converted to the very active isomeric tetrahy-drocannabinols (THC). All parts of the plant, male or female, contain the active material, except the stem, root and seeds. It is a CNS stimulant. It is known as pot, grass, dope, weed, hash, mary jone, M.J., hashish or bhang.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The highest active principle content is found in which part of the cannabis plant?", "options": [{"label": "A", "text": "Root", "correct": false}, {"label": "B", "text": "Resin", "correct": true}, {"label": "C", "text": "Seed", "correct": false}, {"label": "D", "text": "Stem", "correct": false}], "correct_answer": "B. Resin", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Resin CANNABIS SATIVA OR INDICA It is also known as Indian hemp. The active principles are contained in its resin. The principal constituent of the resin is cannabinol. Charas or hashish is the resin (dope or shit) exuding from the leaves and stems of the plant, and it contains 25% to 40% of the active principle. It is dark green or brown. It is mixed and smoked with tobacco in a pipe or hukka. The smoke is inhaled deeply into the lungs and retained for as long as possible for potent effects. Persons habituated to cannabis, both drinkers and smokers, prefer to smoke or drink in company.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A boy was brought to the emergency in an unconscious state from a train where other passengers were also found unconscious. Which of the following is not a feature of Dhatura poisoning ?", "options": [{"label": "A", "text": "Diplopia", "correct": false}, {"label": "B", "text": "Hyperpyrexia", "correct": false}, {"label": "C", "text": "Drowsiness", "correct": false}, {"label": "D", "text": "Decreased thirst", "correct": true}], "correct_answer": "D. Decreased thirst", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Decreased thirst Datura presents with intense thirst. A, b & c: Dhatura (Datura Fastuosa) Dhatura (Datura Fastuosa) Active principles – Hyoscine, Hyoscyamine & Traces of atropine. Signs & symptoms :- D poisoning/10 Ds Dryness of mouth, Dysphagia Dilated pupils -temporary blindness, photophobia, Dry and hot skin, hyperpyrexia Drunken gait - ataxia Delirium – restless and purposeless, pulls imaginary threads from fingers and threads imaginary needle. Delusions and hallucinations of sight & hearing. Dysuria Drowsiness leading to coma & death. Old phrases: Hot as a hare – temperature, Blind as a bat – disturbed vision. Dry as a bone – intense thirst, Red as a beet – flushing of the Mad as a hen– delusion, hallucination. Fatal dose: 100 seeds (0.6 to 1 gm.), Fatal period – 24 hours. Antidote – Physostigmine Medico-legal importance: Road poison</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted with ingestion of a large amount of bhang from a local vendor. Bhang, Ganja, Charas, and Hashish are different preparations of", "options": [{"label": "A", "text": "Barbiturates.", "correct": false}, {"label": "B", "text": "Cannabis.", "correct": true}, {"label": "C", "text": "Cocaine.", "correct": false}, {"label": "D", "text": "Opium.", "correct": false}], "correct_answer": "B. Cannabis.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cannabis. Cannabis sativa or indica (Indian hemp) World’s most commonly used illicit drug, poor man drug Active principle – tetra-hydro-cannabinol (THC) Different preparations: Bhang – mildest, prepared from dried leaves (15%). Majoon – sweet prepared with bhang. Ganja – prepared from flower tops of the female plants (15 to 25 %). Charas or hashish – resin exuding from leaves and stems (25 to 40%) Marihuana/ Marijuana - Mexican term: pleasurable feeling Cannabis American -cut leaves and flowering tops are rolled into cigarettes called ‘reefers or pot. Signs & symptoms – excitement with visual hallucinations, uncontrollable laughter, talkativeness, a marked increase in appetite, loss of perception of time & space, and consciousness changes into a dreamy Cannabis addiction: Hashish insanity –Hallucinations and delusions of a persecuting nature and sexual infidelity (morbid jealousy). Run Amok</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was found smoking pot and creating a ruckus in front of a local hospital. Reefer or pot is related to:", "options": [{"label": "A", "text": "Cocaine", "correct": false}, {"label": "B", "text": "Marijuana", "correct": true}, {"label": "C", "text": "Smack", "correct": false}, {"label": "D", "text": "Amphetamine", "correct": false}], "correct_answer": "B. Marijuana", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Marijuana Cannabis sativa or indica (Indian hemp) World’s most commonly used illicit drug, poor man drug Active principle – tetra-hydro-cannabinol (THC) Different preparations: Bhang – mildest, prepared from dried leaves (15%). Majoon – sweet prepared with bhang. Ganja – prepared from flower tops of the female plant (15 to 25 %). Charas or hashish – resin exuding from leaves and stems (25 to 40%) Marihuana/ Marijuana - Mexican term: pleasurable feeling Cannabis American -cut leaves and flowering tops are rolled into cigarettes called ‘reefers or pot’. Signs & symptoms – excitement with visual hallucinations, uncontrollable laughter, talkativeness, a marked increase in appetite, loss of perception of time & space, and consciousness changes into a dreamy state.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 25 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A poisoning case was admitted in an unconscious state. Junior residents were asking about starting activated charcoal. Activated charcoal is ineffective in the poisoning of:", "options": [{"label": "A", "text": "Acetaminophen", "correct": false}, {"label": "B", "text": "Phenothiazines", "correct": false}, {"label": "C", "text": "Barbiturates", "correct": false}, {"label": "D", "text": "Ethyl alcohol", "correct": true}], "correct_answer": "D. Ethyl alcohol", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ethyl alcohol Barbiturates, atropine, benzodiazepines, opiates, quinine, strychnine, phenothiazines, digitalis, amphetamines, antidepressants, antiepileptics, antihistamines, chloroquine, cimetidine, tetracycline, theophylline, pyrethrins, aluminium phosphide are well adsorbed by activated charcoal.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Sodium fluoride is essentially added to the blood in cases of estimation of:", "options": [{"label": "A", "text": "Blood cyanide levels", "correct": false}, {"label": "B", "text": "Blood arsenic levels in chronic poisoning", "correct": false}, {"label": "C", "text": "Blood alcohol levels", "correct": true}, {"label": "D", "text": "Blood cholesterol levels", "correct": false}], "correct_answer": "C. Blood alcohol levels", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Blood alcohol levels Blood samples should be preserved by the addition of 100 mg. of sodium fluoride and 30 mg. of potassium oxalate for 10 ml. followed by thorough shaking. This prevents the loss of alcohol by glycolysis and bacterial action. Such samples will maintain their alcohol concentration for several weeks, even at room temperature. 50 mg. of phenyl mercuric nitrate or sodium azide can also be used, as a preservative for 10 ml. of blood or urine. This is also useful in blood glucose estimation.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A lady driver was stopped outside a pub when she was found driving under influence of alcohol. In India, the statutory limit of alcohol as per the Motor Vehicle Act is", "options": [{"label": "A", "text": "20 mg %", "correct": false}, {"label": "B", "text": "30 mg %", "correct": true}, {"label": "C", "text": "50 mg%", "correct": false}, {"label": "D", "text": "100 mg %", "correct": false}], "correct_answer": "B. 30 mg %", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>30 mg % The statutory limit in India is 30 mg% (S.l85, Motor Vehicle Act, 1988). The punishment for the first offence is fine of up to Rs. 2,000- or 6-month imprisonment or both, and for a second or subsequent offence fine of up to 3000 or imprisonment of up to 2 years or both.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following is the most reliable method of estimating blood alcohol level?", "options": [{"label": "A", "text": "Cavett’s test", "correct": false}, {"label": "B", "text": "Breathe alcohol analyzer", "correct": false}, {"label": "C", "text": "Gas-liquid chromatography", "correct": true}, {"label": "D", "text": "Thin layer chromatography", "correct": false}], "correct_answer": "C. Gas-liquid chromatography", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Gas-liquid chromatography For medicolegal purposes, the most desirable is gas chromatography in which specificity can be ascertained for estimating blood alcohol levels. Presumptive tests which measure the presence of any volatile reducing agent are routinely done. The basic principle is a reduction of potassium bichromate by the test substance. Kozelka and Hine's test is a macro-method. The Cavett test is a micro-method. Many procedures are employed for determining the values of ethyl alcohol, including headspace and direct injection gas chromatography, enzyme spectrophotometric assays and oxidation techniques.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Breathalyser analyses alveolar air alcohol level and converted it to blood alcohol level with the help of mathematical formula based on Henry’s law. The concentration of alcohol in one ml. of blood is equal to that found in", "options": [{"label": "A", "text": "100ml of alveolar air", "correct": false}, {"label": "B", "text": "1000ml of alveolar air", "correct": false}, {"label": "C", "text": "1500ml of alveolar air", "correct": false}, {"label": "D", "text": "2100ml of alveolar air", "correct": true}], "correct_answer": "D. 2100ml of alveolar air", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>2100ml of alveolar air 2100 to 2300 ml. of alveolar air contains the same amount of alcohol as one ml of blood. This is based on Henry's law, which states that when a volatile chemical (ethanol) is dissolved in a liquid (blood) and is brought· to equilibrium with air (alveolar air) there is U, the ratio between the concentration of the volatile compound (ethanol) in the air (alveolar air) and its concentration in the liquid (blood), and the ratio is constant at a given temperature. (i.e. in alcohol34°C, i.e. the temperature of breathed-out air).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person dies due to hanging. He was suspected to consume alcohol before the act. The most preferred site for the collection of blood in alcohol poisoning is", "options": [{"label": "A", "text": "Femoral vein", "correct": true}, {"label": "B", "text": "Radial artery", "correct": false}, {"label": "C", "text": "Subclavian vein", "correct": false}, {"label": "D", "text": "Cardiac vein", "correct": false}], "correct_answer": "A. Femoral vein", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Femoral vein Blood sample collection in alcohol poisoning, To clean the skin before withdrawing the blood spirit should not be used and the syringe should not contain even a trace of alcohol. The skin is cleaned with Mercuric chloride. Post-mortem blood alcohol determination is completely valid for 36 hrs after death. 10 ml of blood is collected in a glass vial containing 10 mg of sodium fluoride or 30 ml of potassium oxalate as a The best place to obtain blood is from the femoral or any peripheral vein. In most cases, femoral blood is more likely to be a better indicator of the perimortem concentration of the analyte. Peripherally located blood (e.g. from femoral veins) is preferable because it is relatively isolated from the internal organs in the chest and abdomen (blood obtained from the heart or other central regions in the chest and abdomen may have falsely elevated drug levels due to postmortem drug diffusion from the stomach) In embalmed bodies, alcohol can be estimated either in vitreous or in muscle.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B & C: They are good alternatives for the femoral vein. Option D: Cardiac vein is the central vein and is not recommended.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The Viscera sample is to be preserved till the analysis. Preservative used for samples of alcohol poisoning is", "options": [{"label": "A", "text": "Formalin", "correct": false}, {"label": "B", "text": "Methyl alcohol", "correct": false}, {"label": "C", "text": "Saturated solution of NaCI", "correct": true}, {"label": "D", "text": "10% carbolic acid", "correct": false}], "correct_answer": "C. Saturated solution of NaCI", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Saturated solution of NaCI Preservatives used in poisoning cases & Rabies- All poisoning cases- saturated soln. of common salt, Acid poisoning- rectified spirit (95%ethanol + 5% methanol), EXCEPT- Carbolic acid- Thymol. Blood for Alcohol- NaF. Urine- Thymol. Faeces- rectified spirit. CO, HCN- liquid paraffin or no preservative if fresh. As, Pb - 15 cm long bone. Rabies - 50% glycerol saline, keep hippocampus, cerebral cortex, cerebellum, and medulla.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Formalin is used for histopathology Option: B & D. Methyl alcohol and carbolic acid are not used as preservatives.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The pigmentation of tissues shown in the image is seen in", "options": [{"label": "A", "text": "Formic acid poisoning", "correct": false}, {"label": "B", "text": "Carbolic acid poisoning", "correct": true}, {"label": "C", "text": "Oxalic acid", "correct": false}, {"label": "D", "text": "Hydrochloric acid", "correct": false}], "correct_answer": "B. Carbolic acid poisoning", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893671239-QTDF064011IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Carbolic acid poisoning CHRONIC CARBOLIC ACID POISONING (PHENOL MARASMUS):- It is characterised by anorexia, weight loss, headache, vertigo, dark urine and pigmentation of the skin and sclera.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Putrefaction is delayed in poisoning due to:", "options": [{"label": "A", "text": "Carbolic acid", "correct": true}, {"label": "B", "text": "Organophosphorus", "correct": false}, {"label": "C", "text": "Lead", "correct": false}, {"label": "D", "text": "Nux vomica", "correct": false}], "correct_answer": "A. Carbolic acid", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Carbolic acid Putrefaction is delayed after death due to wasting diseases, anaemia, severe haemorrhage, debility, poisoning by carbolic acid, zinc chloride, strychnine and chronic heavy metal poisoning, due to the preservative action of such substances on the tissues or their destructive or inhibitive action on organisms, which influence decomposition.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A white, hardened, and leathery appearance of the mucous membrane of the stomach is seen in:", "options": [{"label": "A", "text": "Sulphuric acid", "correct": false}, {"label": "B", "text": "Carbolic acid", "correct": true}, {"label": "C", "text": "Hydrochloric acid", "correct": false}, {"label": "D", "text": "Acetic acid", "correct": false}], "correct_answer": "B. Carbolic acid", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Carbolic acid In the case of carbolic acid poisoning, the stomach mucosal folds are swollen and covered by opaque, coagulated, grey or brown mucous membranes. The intervening furrows are usually less damaged, dark red and are not opaque. The mucous membrane is thickened and looks leathery. Often there is partial separation of necrotic mucosa, with severe congestion of underlying tissue. The stomach may contain a reddish fluid mixed with mucus and shreds of epithelium and smells of phenol.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The cooling of the body ('chill of death') after death is a complex process, which does not occur at the same rate throughout the body. What is this post-mortem change termed?", "options": [{"label": "A", "text": "Rigor mortis", "correct": false}, {"label": "B", "text": "Algor mortis", "correct": true}, {"label": "C", "text": "Marbling", "correct": false}, {"label": "D", "text": "Livor mortis", "correct": false}], "correct_answer": "B. Algor mortis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Algor mortis The body heat is mostly lost by conduction and convection. In non-contact areas, heat exchange occurs by a conventional mechanism, which exceeds that of the contact surface. Heat exchange by radiation is extensive for the first hour, but decreases later, depending on the rapid decrease in skin temperature. Only a small fraction of heat is lost by the evaporation of fluid from the skin. For about half to one hour after death, the rectal temperature falls little or not at all. ( post-mortem temperature plateau). This is followed by a linear rate of cooling (between 0.4 to 0.6°C per hour) for the next 12 to 16 hours. Then the cooling rate is relatively uniform in its slope. Then it gradually becomes slower, and when the temperature is within about 4°C of the environment, the rate of cooling becomes very slow.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Rigor mortis Rigor mortis (death stiffening; cadaveric rigidity) is a state of stiffening of muscles, sometimes with slight shortening of the fibres. Individual cell death takes place in this stage. Option: Marbling The superficial veins especially over the roots of the limb, thighs, sides of the abdomen, shoulders, chest and neck are stained greenish-brown or purplish-red depending on the total amount of sulphhaemoglobin formation within the affected vessels (linear branching pattern) due to the haemolysis of red cells, which stains the wall of the vessel and infiltrates into the tissue, giving a marbled appearance (red, then the greenish pattern in skin resembling the branches of a tree). Option: D. Livor mortis. This is the bluish-purple or purplish-red (due to deoxyhaemoglobin) discolouration, which appears under the skin in the most superficial layers of the dermis (rete mucosum) of the dependent parts of the body after death, due to capillo-venous distention.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In which condition, the temperature of the body remains raised for the first two hours or so after death?", "options": [{"label": "A", "text": "Algor mortis", "correct": false}, {"label": "B", "text": "Postmortem Caloricity", "correct": true}, {"label": "C", "text": "Rigor mortis", "correct": false}, {"label": "D", "text": "Livor mortis", "correct": false}], "correct_answer": "B. Postmortem Caloricity", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Postmortem Caloricity This occurs: When the regulation of heat production has been severely disturbed before death, as in sunstroke and in some nervous disorders, When there has been a great increase in heat production in the muscles due to convulsions, as in tetanus and strychnine poisoning, etc., When there has been excessive bacterial activity, as in septicaemic conditions. cholera and other fevers.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Algor mortis The body heat is mostly lost by conduction and convection. In non-contact areas, heat exchange occurs by a conventional mechanism, which exceeds that of the contact surface. Heat exchange by radiation is extensive for the first hour, but decreases later, depending on the rapid decrease in skin temperature. Only a small fraction of heat is lost by the evaporation of fluid from the skin. For about half to one hour after death, the rectal temperature falls little or not at all. (postmortem temperature plateau). This is followed by a linear rate of cooling (between 0.4 to 0.6°C per hour) for the next 12 to 16 hours. Then the cooling rate is relatively uniform in its slope. Then it gradually becomes slower, and when the temperature is within about 4°C of the environment, the rate of cooling becomes very slow. Option: C. Rigor mortis Rigor mortis (death stiffening; cadaveric rigidity) is a state of stiffening of muscles, sometimes with slight shortening of the fibres. Individual cell death takes place in this stage. Option: D. Livor mortis This is the bluish-purple or purplish-red (due to deoxyhaemoglobin) discolouration, which appears under the skin in the most superficial layers of the dermis (rete mucosum) of the dependent parts of the body after death, due to capillo-venous distention.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Heat is generated by a residual metabolic process called glycogenolysis. How does this process affect the post-mortem change, algor mortis?", "options": [{"label": "A", "text": "Cools down the body faster", "correct": false}, {"label": "B", "text": "Slows down the cooling initially", "correct": true}, {"label": "C", "text": "Doesn’t have any effect on algor mortis", "correct": false}, {"label": "D", "text": "None of the options are right", "correct": false}], "correct_answer": "B. Slows down the cooling initially", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Slows down the cooling initially The heat generated by this process of glycogenolysis slows down the rate of cooling in the beginning. Slows down the cooling sometimes Heat is generated by the residual metabolic process (glycogenolysis) of dying tissues and by the metabolic activity of intestinal bacteria, due to which body temperature does not fall for some time. With the start of cooling, a temperature gradient develops from the surface to the core of any part of the body. The exchange of heat between the core and the surface of the body occurs only by conduction. At first, the heat is lost from superficial layers of the body only.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Cools down the body faster Not correct Option: C. Doesn’t have any effect on algor mortis Not correct Option: D. None of the options are right Not correct</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Statement 1: Postmortem Caloricity: In this condition, the temperature of the body remains raised for the first two hours or so after death. Statement 2: This occurs when the regulation of heat production has been severely disturbed before death, as in sunstroke and some nervous disorders", "options": [{"label": "A", "text": "Both statements are wrong", "correct": false}, {"label": "B", "text": "Both statements are right", "correct": true}, {"label": "C", "text": "Statement 1 is right but 2 isn’t the right explanation for it", "correct": false}, {"label": "D", "text": "Statement 2 is right but 1 is wrong", "correct": false}], "correct_answer": "B. Both statements are right", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both statements are right Post-mortem Caloricity: In this condition, the temperature of the body remains raised for the first two hours or so after death. This occurs: When the regulation of heat production has been severely disturbed before death, as in sunstroke and in some nervous disorders, When there has been a great increase in heat production in the muscles due to convulsions, as in tetanus and strychnine poisoning, etc., When there has been excessive bacterial activity, as in septicaemic conditions. cholera and other fevers.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Both statements are wrong and can’t be correct Option: C. Statement 1 is right but 2 isn’t the right explanation for it Not correct Option: D. Statement 2 is right but 1 is wrong Not correct</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The cooling of the body ('chill of death') after death is a complex process, which does not occur at the same rate throughout the body. Which of the following factors slows down algor mortis?", "options": [{"label": "A", "text": "Cold environment", "correct": false}, {"label": "B", "text": "Body’s found in water sources", "correct": false}, {"label": "C", "text": "Covering on or around the body", "correct": true}, {"label": "D", "text": "A body kept in a well-ventilated room", "correct": false}], "correct_answer": "C. Covering on or around the body", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Covering on or around the body The rate of cooling is slow when the body is clothed, as clothes are bad conductors of heat. A bedspread covering may at least halve the rate of cooling.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Cold A body in zero weather may undergo freezing and become stony-hard from the formation of ice in cavities and blood vessels. Option: B. Body found in water sources Cooling in water is rapid because water is a far better conductor of heat. Cooling in still water is about twice as fast as in air, and flowing water is about three times as fast. Bodies cool more slowly in water containing sewage effluent or other putrefying organic material than in freshwater or seawater. Option: D. A body kept in a well-ventilated room A body kept in a well-ventilated room will cool more rapidly than one in a closed room. Moist air is a better conductor of heat than dry air, so cooling is more rapid in a humid atmosphere than in a dry atmosphere.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Rigor mortis is the state of stiffening of muscles with very little shortening of muscle fibres. It is seen in both voluntary and involuntary muscles. Rigor mortis is first seen in the involuntary muscle which is the myocardium. Followed by voluntary muscles. Among voluntary groups of muscles, the Appearance of Rigor mortis follows Nysten’s rule. What is Nysten’s rule?", "options": [{"label": "A", "text": "Rigor mortis appears first in the muscles near the brain and last in muscles far away from the brain.", "correct": true}, {"label": "B", "text": "Rigor mortis appears first in the muscles far away from the brain and last in the muscles near the brain.", "correct": false}, {"label": "C", "text": "Rigor mortis starts setting from where the person was injured first.", "correct": false}, {"label": "D", "text": "Rigor mortis starts setting in from Toe to head.", "correct": false}], "correct_answer": "A. Rigor mortis appears first in the muscles near the brain and last in muscles far away from the brain.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Rigor mortis appears first in the muscles near the brain and last in muscles far away from the brain. Proximal to the distal appearance of Rigor mortis is: Eyes lids – 3 to 4 hours Muscle of jaws Facial muscles Neck Chest Upper limbs Abdomen Lower limbs Fingers and toes</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Rigor mortis appears first in muscles far away from the brain and last in the muscles near the brain is also a wrong explanation. Option C. Rigor mortis starts setting from where the person was injured first. Not correct Option D. Rigor mortis starts setting in from Toes to head is also a wrong option</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "How much time is taken for a complete set of rigor mortis?", "options": [{"label": "A", "text": "8 hours since death", "correct": false}, {"label": "B", "text": "5 hours since death", "correct": false}, {"label": "C", "text": "12 hours since death", "correct": true}, {"label": "D", "text": "16 hours since death", "correct": false}], "correct_answer": "C. 12 hours since death", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>12 hours since death It takes 12 hours for rigor mortis to completely set in a dead body. It persists on all the parts of the body for the next 12 hours. It disappears from the body after the next 12 hours.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. 8 hours since death Not correct Option: B. 5 hours since death Not correct Option: D. 16 hours since death Not correct</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person in his early 30s died succumbing to his injuries from a motorcycle accident in a hospital. His body mass index was high and was above 100 kgs. Algor mortis in usual cases starts setting in after 2 hours of death. But in this case, it was delayed. What caused the delay?", "options": [{"label": "A", "text": "Fat bodies cool slowly and lean bodies rapidly.", "correct": true}, {"label": "B", "text": "Body mass index has a connection to the cooling down of the body", "correct": false}, {"label": "C", "text": "Algor mortis takes time for setting in for the adult body", "correct": false}, {"label": "D", "text": "None of these", "correct": false}], "correct_answer": "A. Fat bodies cool slowly and lean bodies rapidly.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Fat bodies cool slowly and lean bodies rapidly. The physique of the cadaver: Fat is a bad conductor of heat.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Body mass has no connection to cooling down of the body The physique of the cadaver does impact the cooling down of the body. Fat bodies cool slowly and lean bodies rapidly. Option: C. Algor mortis takes time for setting in for the adult body Algor mortis starts setting in a cadaver irrespective of age.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A laboratory thermometer 25 cm. long, with a range of 0 to 50°C. which can be read in single degrees is used. The rectum is the ideal place to record temperature except in cases of sodomy. The thermometer should be inserted 8 to 10 cm. and left there for two minutes. What other ways can temperature be recorded?", "options": [{"label": "A", "text": "The temperature can also be recorded by making a small opening into the peritoneal cavity and inserting the thermometer in contact with the inferior surface of the Liver.", "correct": false}, {"label": "B", "text": "The external auditory meatus or the nasal passages also can be used to record the temperature.", "correct": false}, {"label": "C", "text": "Nose is used, the probe or bulb should be passed up to the cribriform plate, and in the ear, should be placed on or through the tympanic membrane.", "correct": false}, {"label": "D", "text": "All methods are correct", "correct": true}], "correct_answer": "D. All methods are correct", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All methods are correct Option: A. The temperature can also be recorded by making a small opening into the peritoneal cavity and inserting the thermometer in contact with the inferior surface of the Liver. Option: B. The external auditory meatus or the nasal passages also can be used to record the Option: C. Nose is used, the probe or bulb should be passed up to the cribriform plate, and in the ear, should be placed on or through the tympanic membrane. Option: D. All are right</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The cooling of the body ('chill of death') after death is a complex process, which does not occur at the same rate throughout the body. The body will not cool according to Newton's law. After the stoppage of circulation, the convectional transport of heat inside the body stops. What are the Factors Affecting the Rate of Cooling?", "options": [{"label": "A", "text": "The build of the cadaver", "correct": false}, {"label": "B", "text": "The physique of the cadaver", "correct": false}, {"label": "C", "text": "Covering on or around the body", "correct": false}, {"label": "D", "text": "All of these", "correct": true}], "correct_answer": "D. All of these", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of these The difference in temperature between the body and the medium: The temperature fall is rapid when the difference between body and air temperature is great. In India, during summer, the temperature of the environment may be higher than that of the body temperature, and as such the cooling is very slow. In tropical climates, the heat loss is roughly 0.4°C to 0.6°C and in temperate countries 1°C per hour.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . The build of the cadaver: The rate of heat loss is proportional to the weight of the body to its surface area. Thus, children and old people cool more rapidly than adults. Option: B . The physique of the cadaver: Fat is a bad conductor of heat. Fat bodies cool slowly and lean bodies rapidly. The environment of the body: A body kept in a well-ventilated room will cool more rapidly than one in a closed room. Moist air is a better conductor of heat than dry air, so cooling is more rapid in a humid atmosphere than in a dry atmosphere. Cooling in water is rapid because water is a far better conductor of heat. Cooling in still water is about twice as fast as in air, and flowing water is about three times as fast. Bodies cool more slowly in water containing sewage effluent or other putrefying organic material than in freshwater or seawater. Option: C . Covering on or around the body: The rate of cooling is slow when the body is clothed, as clothes are bad conductors of heat. A bread spread covering may at least halve the rate of cooling.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The mechanism of action of sodium nitrite in cyanide poisoning is the formation of", "options": [{"label": "A", "text": "Methemoglobin", "correct": true}, {"label": "B", "text": "Carboxyhemoglobin", "correct": false}, {"label": "C", "text": "Myoglobin", "correct": false}, {"label": "D", "text": "Free radicals", "correct": false}], "correct_answer": "A. Methemoglobin", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Methemoglobin Sodium nitrite + Hb - --> methaemoglobin. Methaemoglobin + Na CN --->Cyanmethemoglobin.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Mechanism of action of Carbon dioxide poisoning", "options": [{"label": "A", "text": "Inhibition of cytochrome oxidase", "correct": false}, {"label": "B", "text": "Combination with haemoglobin", "correct": false}, {"label": "C", "text": "Formation of methemoglobin", "correct": false}, {"label": "D", "text": "Prevention of tissues usage of oxygen", "correct": true}], "correct_answer": "D. Prevention of tissues usage of oxygen", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Prevention of tissues usage of oxygen It displaces oxygen from its combination with haemoglobin and forms a relatively stable compound known as carboxyhemoglobin. It thus reduces the oxygen content of the blood, and hence that of the tissues. It acts as a chemical asphyxiant and produces death due to anaemic anoxia. CO is a potent cellular toxin. It effectively and firmly binds to haemoglobin and myoglobin. It inhibits electron transport by blocking cytochrome</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The route of administration of amyl nitrite in cyanide poisoning is:", "options": [{"label": "A", "text": "Intramuscular", "correct": false}, {"label": "B", "text": "Intravenous", "correct": false}, {"label": "C", "text": "Inhalation", "correct": true}, {"label": "D", "text": "Subcutaneous", "correct": false}], "correct_answer": "C. Inhalation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Inhalation In a case of cyanide poisoning, break 0.2 ml. ampoule of amyl nitrite in a handkerchief and hold it over the patient's nose for 15 to 30 seconds every minute, until sodium nitrite infusion is started.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A couple was brought to the ER of a hospital where you were the intern on duty. They presented with increasing confusion, sometimes hallucinations, severe ataxia, rapid respirations and collapse with attempts at exertion. Their symptoms resembled alcohol intoxication but they denied any such use. On taking proper history, it was revealed that they were sleeping in the room all alone and they forgot to turn off the water heater. They also complained of blisters over the buttocks and calves with cherry red discolouration of the mucous membrane. What will be the best management step for this poisoning case?", "options": [{"label": "A", "text": "Giving 0.2ml Amyl nitrite inhalation along with 0.3g Sodium nitrite and 25g Sodium thiosulphate infusion.", "correct": false}, {"label": "B", "text": "100% Oxygen at atmospheric pressure through tight fitting mask along with steroids and antibiotics.", "correct": true}, {"label": "C", "text": "Symptomatic treatment along with Sodium thiosulphate.", "correct": false}, {"label": "D", "text": "Artificial respiration and oxygen should be given along with cardiac stimulants.", "correct": false}], "correct_answer": "B. 100% Oxygen at atmospheric pressure through tight fitting mask along with steroids and antibiotics.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>100% Oxygen at atmospheric pressure through tight fitting mask along with steroids and antibiotics. This is a case of CO (Carbon Monoxide) poisoning indicated by the symptoms and signs by the patient along with the relevant history of sleeping in a closed room with a heating appliance. CO poisoning causes Anemic hypoxia because of the formation of Carboxy haemoglobin – so it should be treated with 100% Oxygen. CO is a colourless, tasteless, non-irritative gas which is produced due to the incomplete combustion of carbon. It is insoluble in water, a yellow flame generates CO while a blue flame burns completely with no byproducts. CO is readily absorbed across the alveoli and combined with haemoglobin. It displaces oxygen from its combination with haemoglobin and forms a relatively stable compound known as Carboxyhemoglobin. It thus reduces the oxygen content of the blood, and hence that of the tissues. It inhibits electron transport by blocking cytochrome A3 oxidase and cytochrome P450 and so blocking intercellular respiration. Symptoms depend on CO concentration in blood- < 10% - No symptoms. 10-20% - Breathless on moderate exertion, headache, weakness. 20-30% - Severe headache, irritability, emotional instability, defective memory. 30-40% - Cherry red discolouration of the skin, mucous membrane, decreased vision, nausea and vomiting. 40-5% - Resemble acute alcoholic intoxication. 50-60% - Syncope and coma. >80% - Death. Treatment - Remove the patient to fresh air immediately, if conscious and breathing, no treatment is required. Otherwise, all patients having > 25% CO should be treated. Use of 100% oxygen at atmospheric pressure and in case of hyperbaric O2- 100% oxygen at pressure. Antibiotics are given as prophylaxis against lung infection, along with steroids.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A. Giving 0.2ml Amyl nitrite inhalation along with 0.3g Sodium nitrite and 25g Sodium thiosulphate infusion is the treatment option for Cyanide poisoning. The principle of the treatment is to reverse the Cyanide-cytochrome combination and excrete the cyanide through urine after converting it to Non- toxic thiocyanate. Option: C. Symptomatic treatment along with Sodium thiosulphate is given in case of MIC (Methyl Isocyanate) poisoning, it is one of the deadliest chemicals and kills in very small doses when ingested, inhaled or absorbed through the skin. Option: D. In case of CO2 poisoning, artificial respiration and oxygen should be given along with cardiac stimulants. It is a heavy, colourless gas with a faintly sweet odour.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The use of non-living toxic products produced by living organisms has increased, which is now considered a new weapon being used by Countries and police to control enemies and riots respectively. In wars various poisonous gases are included and termed “War gases”. Which option correctly matches the type of war gas used? Lung irritants- Ammonia, chlorine, phosgene. Lachrymators- CAP, KSK, BBC Vesicants- Bromobenzyl Cyanide, Phosgene Sternutators- Esters of Phosphoric Acid Nerve gases- Tabun, Sarin. Paralysants- Oleoresin capsaicin Select the answer from given below code:-", "options": [{"label": "A", "text": "1,2,5", "correct": true}, {"label": "B", "text": "3,4,6", "correct": false}, {"label": "C", "text": "1,3,6", "correct": false}, {"label": "D", "text": "2,4,5", "correct": false}], "correct_answer": "A. 1,2,5", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,2,5 War gases are classified under chemical warfare. Any chemical (gaseous, liquid or solid) which is used to produce destruction or damage mostly in times of war is termed a “War Gas”. These are used to injure or kill enemies during war. They produce physiological changes in the human body, some substances are lethal and some injure or incapacitate people. Various types of War gases used are as- Vesicant / Blistering gas - These are mainly sulphur, mustard, phosgene, They are discharged in artillery shells so as to saturate the area of attack. Mustard gas causes irritation of the eyes, nose, throat and respiratory passage. Wash the affected parts thoroughly, eye wash with Sodium bicarbonate. Asphyxiants / Lung irritants - These are chlorine and phosgene which are gases and can be released from tanks and gas shells. When inhaled, they cause watering of the eyes, coughing, dyspnoea, and tightness of the Eyewash with boric acid, oxygen and adrenaline, antitussives, and antibiotics are given. Lachrymators / Tear gases - These are mainly chloroacetophenone (CAP); ethyl iodoacetate (KSK); Bromobenzyl cyanide (BBC), fired in artillery shells or pen guns. The vapours cause intense irritation of the eyes with a copious flow of tears, spasms of eyelids and temporary blindness. Remove the patient to fresh air and wash the eyes with warm normal saline or boric acid. Sternutators / Nasal Irritants - These are solid, organic compounds of arsenic and are fired in artillery shells. They are Diphenylcyanarsine and Diphenyl chlorarsine. The vapours cause intense pain and irritation in the nose and sinuses, nausea, and Paralysants - Hydrocyanic acid, CO, and Sulphuretted hydrogen are examples. Nerve Gases - These are esters of phosphoric acid and are identical to organophosphates. The major agents are- Tabun; Sarin; Soman. They are colourless and odourless volatile agents, absorbed from lungs, GIT, skin, etc. It is the correct match, war gases like Lung irritants, lachrymators, and nerve gases are given with their correct examples.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Vesicants, Sternutators, and Paralysants are wrongly matched with their options. Their correct examples are- Vesicant / Blistering gas - These are mainly sulphur, mustard, and Sternutators - Diphenylcyanarsine, Diphenyl chlorarsine. Paralysants - Hydrocyanic acid, CO, Sulphuretted hydrogen. Option: C. Vesicants and Paralysants are wrongly matched. Option: D. Sternutators are wrongly matched with the example, its correct example is as -solid, organic compounds of arsenic known as Diphenylcyanarsine, Diphenyl chlorarsine. The vapours cause intense pain and irritation in the nose and sinuses, nausea, and It doesn’t include Esters of Phosphoric Acid</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The autopsy findings of a patient of a poisoning case are given as:- External findings: Cherry red colouration of the skin, mucous membranes, PM staining, blood, tissues and internal organs. Fine froth at the nostrils/ mouth, and blisters at dependent body parts such as buttocks, calves, and wrists were present. Internal findings: Lungs were edematous and congested, rhabdomyolysis and renal failure, and softening of the cerebral cortex and corpus striatum were seen.The patient was poisoned with which of the following poisons?", "options": [{"label": "A", "text": "CO", "correct": true}, {"label": "B", "text": "Tear Gas", "correct": false}, {"label": "C", "text": "MIC", "correct": false}, {"label": "D", "text": "Hydrogen Sulphide", "correct": false}], "correct_answer": "A. CO", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>CO The given autopsy findings are of CO poisoning. CO poisoning causes anaemic hypoxia by causing the formation of Carboxy Hemoglobin and a leftward shift of the Oxyhemoglobin dissociation curve. CO is a colourless, tasteless, non- irritative and odourless gas and is lighter than air. It is produced by incomplete combustion of Carbonaceous material, and on combining with chlorine it forms Carbonyl chloride (phosgene). It is produced by tobacco smoke, house fires, automobile exhaust (1-7% CO), faulty heating units (stoves, water heaters), coal gas, and endogenous CO. CO causes inhibition of electron transport by blocking cytochrome oxidase A3 and cytochrome P450 and hence intracellular respiration. CO is a colourless, tasteless, non-irritative and odourless gas and lighter than air. Symptoms depend on CO concentration in blood- < 10% - No symptoms. 10-20% - Breathless on moderate exertion, headache, weakness. 20-30% - Severe headache, irritability, emotional instability, defective memory. 30-40% - Cherry red discolouration of the skin, mucous membrane, decreased vision, nausea and vomiting. 40-5% - Resemble acute alcoholic intoxication. 50-60% - Syncope and coma. >80% - Death. Treatment - Remove the patient to fresh air immediately, if conscious and breathing, no treatment is required. Otherwise, all patients having > 25% CO should be treated. Use of 100% oxygen at atmospheric pressure and in case of hyperbaric O2- 100% oxygen at pressure. Antibiotics are given as prophylaxis against lung infection, along with steroids. Differential diagnosis- Alcohol intoxication; Head injury; Diabetic/ Insulin coma; Uremia; Cerebral haemorrhage; Narcotic poisoning. Autopsy findings evident of CO poisoning are- Cherry red colour discolouration of the skin, mucous membrane, blood, blisters are subcutaneous and over-dependent parts of body, buttocks, calves, knee along with B/L symmetrical necrosis of globus pallidus and putamen. CO - It is a colourless, tasteless, non- irritative and odourless gas and is lighter than air. It is produced by the incomplete combustion of carbonaceous material.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Tear Gas - It is mainly chloroacetophenone (CAP); ethyl iodoacetate (KSK); Bromobenzyl cyanide (BBC), fired in artillery shells or pen guns. The vapours cause intense irritation of the eyes with a copious flow of tears, spasms of eyelids and a temporary blindness. Option: C. MIC - It is a colourless, highly flammable liquid with a pungent odour that evaporates quickly when exposed to the air. It causes respiratory failure from Acute lung injury or acute respiratory distress syndrome (ARDS). Option: D. Hydrogen Sulphide - It is a colourless, heavy, flammable gas. Hydrogen sulphide in combination with CO2 and methane formed in sewers is known as Sewer Gas. The PM appearance is characterised by a rotten egg odour along with the general sign of asphyxia and the colour of blood and viscera and bronchial secretions is greenish-purple.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The poison produced from the seeds shown below causes petechial haemorrhages under the skin and peritoneum. These seeds are", "options": [{"label": "A", "text": "Abrus precatorius", "correct": true}, {"label": "B", "text": "Castor", "correct": false}, {"label": "C", "text": "Cannabis", "correct": false}, {"label": "D", "text": "Dhatura", "correct": false}], "correct_answer": "A. Abrus precatorius", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893713858-QTDF066001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Abrus precatorius The seeds of Abrus precatorius are egg-shaped, bright scarlet colour with a large black spot at one end, 8 mm. long and 6 mm. broad, and weigh 105 mg. on average. Seeds may be white with black spots, all black, yellow or blue. The seeds contain an active principle abrin, a TOX albumen, which is similar to viperine snake venom; also present are abrine (N-methyl tryptophan), an amino acid, hemagglutinin in the cotyledons; a lipolytic enzyme, and abralin, a glucoside. All parts of the plant are poisonous. Seeds are tasteless and odourless. Abrin inhibits protein synthesis and causes cell death. Suis are produced from these seeds to attack cattle. The presentation of the poison is just like viper snake envenomation with haemorrhages into the mucosa and internal organs.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient took some unknown drug with the intent to commit suicide. He has now developed blisters over the skin. The presence of skin blisters is suggestive of poisoning by:", "options": [{"label": "A", "text": "Arsenic", "correct": false}, {"label": "B", "text": "Barbiturates", "correct": true}, {"label": "C", "text": "Cocaine", "correct": false}, {"label": "D", "text": "Carbon dioxide", "correct": false}], "correct_answer": "B. Barbiturates", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Barbiturates Blisters on the skin, often on an area of erythema, strongly suggest barbiturate poisoning. Blisters contain clear serous fluid. The rupture of a blister leaves a red, raw surface which later dries to a brown parchment-like area. They are commonly found in sites where pressure has been exerted between two skin surfaces, such as the interdigital clefts and inner aspects of the knees, buttocks, backs of thighs, calves and forearms.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was arrested after he was found carrying heroin in his stomach in packets. Illegal drugs packed in condoms then swallowed and transported are called:", "options": [{"label": "A", "text": "Main lining", "correct": false}, {"label": "B", "text": "Body stuffer", "correct": false}, {"label": "C", "text": "Body packer", "correct": true}, {"label": "D", "text": "Snorting", "correct": false}], "correct_answer": "C. Body packer", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Body packer BODY PACKER (SURGICAL MULES) SYNDROME: Illegal drugs, such as cocaine, heroin, amphetamine and cannabis are compressed into cylinders of about 25x12 mm in size, heat-sealed in plastic film and wrapped again in multiple layers of latex (condoms, balloons, foil, fingers of rubber gloves, etc.) and swallowed.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was under the effect of phenobarbitone. True about Severe Barbiturate poisoning EXCEPT:", "options": [{"label": "A", "text": "Hypothermia", "correct": false}, {"label": "B", "text": "Hypertension", "correct": true}, {"label": "C", "text": "Coma", "correct": false}, {"label": "D", "text": "Non-reactive pupil", "correct": false}], "correct_answer": "B. Hypertension", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hypertension Toxic symptoms of barbiturate-sedative action on the CNS. Large doses-neuromuscular blockade. Intravenous injection-peripheral vasodilation -fall in BP, shock. ↓se alveolar ventilation (↓se PO2, ↑se PCO2 ). Induce CO2 narcosis in persons with COPD. Respiratory depressant effect with sedative drugs- concomitantly taken. The death occurred in persons who were concurrently injected with ethanol / CNS depressant. IV dosing-hypotension & respiratory depression-death. Slurred speech Ataxia Lethargy Confusion Headache Nystagmus CNS depression Coma Shock Constricted pupils.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 14 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A cloth piece was recovered from a crime scene along with a dead body. The cloth piece was stained with some reddish brown stains. The most reliable test for the identification of a blood stain is:", "options": [{"label": "A", "text": "Benzidine test", "correct": false}, {"label": "B", "text": "Takayama test.", "correct": false}, {"label": "C", "text": "Teichmann’s test", "correct": false}, {"label": "D", "text": "Spectroscopic test", "correct": true}], "correct_answer": "D. Spectroscopic test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Spectroscopic test It is the most delicate and reliable test for detecting the presence of blood in both recent and old stains. Less than 0.1 mg. of blood is sufficient. The blood stain is dissolved in water, normal saline or dilutes ammonia, and is placed in a small glass test tube which is then kept between the spectroscope and the source of the light. The extract of the blood must be diluted and if turbid it should be filtered. The solution of the blood has the property of absorbing some of the rays from the spectrum, producing characteristic dark absorption bands, which vary with the type of blood pigment present.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Benzidine Test Cut out a small piece of old stained material or tease out fibres from the stained fabric and place it on porcelain tile. Add a drop of a saturated solution of benzidine in glacial acetic acid, and then a drop of 10 volumes of hydrogen peroxide. If blood is present, a dark blue colour is produced immediately. A positive reaction is given by blood of almost any age, blood that has been exposed to heat or cold, and blood stains treated with cleaning agents. This is the best preliminary test for blood and it detects blood when present in a dilution of one part of blood in three lakhs. A positive reaction is not proof of the presence of blood, but a negative reaction rules out the presence of blood. A weaker reaction is obtained from certain other substances, e.g. pus, saliva, milk, rust, formalin, certain vegetable and animal juices, oxidising agents, bacteria, etc. Option: B. Haemochromogen Crystal Test (Takayama tes t ) Place a small piece of suspected material on a glass slide and add 2 to 3 drops of Takayama reagent (sodium hydroxide, pyridine. glucose), and cover with a coverslip. Pink feathery crystals of haemo chromogen or reduced alkaline haematin arranged in clusters, sheaves, etc., appear in one to six minutes. Slight warming of the slide hastens the reaction. The result is negative if crystals are not formed in 30 minutes. The test gives good results even with old stains. It is delicate and more reliable. Option: C. Haemin Crystal Test (Teichmann's test) A small crystal of sodium chloride and two to three drops of glacial acetic acid are placed on a small piece of the suspected stain on a glass slide. A coverslip is applied and. the acid is evaporated by heating over a small flame. It is examined under the microscope after cooling. Faint yellowish-red to brownish-black rhombic crystals of haemin or haematin chloride arranged single or in clusters are seen if blood is present. Bubbles of gas are given by haematin crystals, with the addition of a drop of hydrogen peroxide. The reaction is negative if the stain is old, is washed or treated by chemicals, presence of too much salt, moisture in acid and overheating.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A positive Kastle Mayer test is indicated by the development of which colour in the stained area:", "options": [{"label": "A", "text": "Blue colour", "correct": false}, {"label": "B", "text": "Pink colour", "correct": true}, {"label": "C", "text": "Green colour", "correct": false}, {"label": "D", "text": "Luminescent", "correct": false}], "correct_answer": "B. Pink colour", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pink colour Phenolphthalein Test (Kastle-Meyer Test): To a solution extracted from the stain with distilled water, add ten to twenty drops of phenolphthalein reagent (phenolphthalein 2g. + sodium hydroxide 20g. + zinc+ distilled water 100 ml), and then a drop or two of 10 volumes hydrogen peroxide. If blood is present, a pink or purple colour develops immediately. The test is more specific for blood than the benzidine test but comparatively less sensitive. Traces of copper give a positive reaction. The tests employing guaiacum (deep blue) and leucomalachite green are rarely used in medico-legal work.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A mother comes to the police claiming one person as the father of her one-month-old child. Disputed paternity can be solved by using the following tests except:", "options": [{"label": "A", "text": "Blood grouping", "correct": false}, {"label": "B", "text": "HLA typing", "correct": false}, {"label": "C", "text": "Precipitin test", "correct": true}, {"label": "D", "text": "DNA fingerprinting", "correct": false}], "correct_answer": "C. Precipitin test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Precipitin test Species identification can be done by precipitin test, hence can't be used for disputed paternity . A blood group antigen cannot appear in a child, unless present in one or another reaction. If an individual is homozygous for a blood group factor, it must appear in the blood of all his children. If a child is homozygous for a blood group factor, the gene for the same must have been inherited by it from each of its parents. The blood group characters are peculiar to the individual and are unchanged throughout life.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Blood grouping :- The application of blood groupings to medicolegal problems is based on the following principles. Option: B. HLA Typing :- The Human Leucocyte Antigen (HLA) System consists of protein substances on the surface of a wide variety of tissues and organs, on tumours, white cells ASD platelets. The presently known seven multiple loci with about 125 multiple allelism, and with a very high degree of polymorphism, provide a very good discriminating capacity. Option: D. DNA fingerprinting (DNA typing, DNA identification, or genetic typing) is a technique involving chemically dividing the DNA into fragments which form a unique pattern and then matching that \"identity profile\" with the pattern obtained from similarly testing a suspect's blood specimen. If the two patterns match, the possibility of error, i.e. the chance that they do not belong to the same individual may be less than one in 30 billion.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "All the following are used for the detection of blood stains except:", "options": [{"label": "A", "text": "Benzidine test", "correct": false}, {"label": "B", "text": "Haemin crystal test.", "correct": false}, {"label": "C", "text": "Acid phosphatase test", "correct": true}, {"label": "D", "text": "Malachite green test.", "correct": false}], "correct_answer": "C. Acid phosphatase test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Acid phosphatase test The Acid Phosphatase Test: is used in the chemical analysis of semen. The prostatic secretion element of seminal fluid contains 500 to 1000 times greater acid phosphatase than any other body fluid. Human red cells, semen of higher apes, and juice of cauliflower have acid phosphatase levels similar to that of human semen. The concentration of acid phosphatase gradually falls with time in vaginal secretions, and positive reactions are found for periods of thirty-six hours, with gradual disappearance in 72 hours, but is little changed if the body is refrigerated. Five to ten ml. of normal saline solution is placed in the vagina with a syringe. The fluid is then removed and placed in a sealed tube and refrigerated for enzyme examination. Concentration in excess of hundred Bodansky units with or without motile sperms indicates that ejaculation occurred within twelve hours of examination. Dried seminal stains which have not undergone putrefaction retain acid phosphatase activity for weeks or months, although enzymatic activity decreases slowly with time. The concentration is slowly reduced when the stain is left at room temperature and exposed to light. Heating the specimen to 60 degrees or over destroys it within five minutes. Low levels of acid phosphatase are present in vaginal secretions. In humans, acid phosphatase content is greater than in animals. This test is conclusive in the absence of demonstrable sperms or in aspermia.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Hydrogen peroxide is used in all of the following chemical tests for blood except", "options": [{"label": "A", "text": "Benzidine test.", "correct": false}, {"label": "B", "text": "Phenolphthalein test.", "correct": false}, {"label": "C", "text": "Orthotoluidine test.", "correct": false}, {"label": "D", "text": "Hemochromogen test.", "correct": true}], "correct_answer": "D. Hemochromogen test.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hemochromogen test. Haemochromogen Crystal Test (Takayama test) : Place a small piece of suspected material on a glass slide and add 2 to 3 drops of Takayama reagent (sodium hydroxide, pyridine. glucose), and cover with a coverslip. Pink feathery crystals of haemo chromogen or reduced alkaline haematin arranged in clusters, sheaves, etc., appear in one to six minutes. Slight warming of the slide hastens the reaction. The result is negative if crystals are not formed in 30 minutes. The test gives good results even with old stains. It is delicate and more reliable.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B & C. Chemical tests for blood stains usually use the enzyme hydrogen peroxide. Hence Benznidine, Phenolphthalein and Orthotoluidine test uses peroxide enzyme.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The following statement about blood grouping is correct except:", "options": [{"label": "A", "text": "Can be used to resolve the confusion of identity in the alleged exchange of babies in the maternity unit.", "correct": false}, {"label": "B", "text": "Can conclusively fix the paternity", "correct": true}, {"label": "C", "text": "Can assist in matching fragmented human remains in mass disaster", "correct": false}, {"label": "D", "text": "Can help to show whether blood stain on the weapon belongs to the suspect or victim.", "correct": false}], "correct_answer": "B. Can conclusively fix the paternity", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Can conclusively fix the paternity Medicolegal Aspects of Blood Groups: The application of blood groupings to medicolegal problems is based on the following principles: A blood group antigen cannot appear in a child, unless present in one or another If an individual is homozygous for a blood group factor, it must appear in the blood of all his children. If a child is homozygous for a blood group factor, the gene for the same must have been inherited by it from each of its parents. The blood group characters are peculiar to the individual and are unchanged throughout life.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 7-year-old male was admitted with diffuse muscle rigidity & facial spasm having a strange smile on his face. The mother gave a history that her son ingested some unknown substance in a neighbour’s home. What can be the responsible substance?", "options": [{"label": "A", "text": "Opium", "correct": false}, {"label": "B", "text": "Strychnine", "correct": true}, {"label": "C", "text": "Mercury", "correct": false}, {"label": "D", "text": "Calotropis", "correct": false}], "correct_answer": "B. Strychnine", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891587217-QTDF003008IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Strychnine Trychnine Poisoning:- Strychnine is an odourless white crystalline prism that melts at 275 to 285 degrees C with decomposition. It is very bitter in taste and more powerful than brucine Mechanism of action:- Strychnine antagonizes the inhibitory neurotransmitter amino-acid glycine at postsynaptic receptors. Inhibitory glycine receptors are abundant in the spinal cord and brain stem where they are mainly involved in the regulation of motor functions. When inhibitors are blocked, ongoing neuronal excitability is increased and sensory stimuli produce exaggerated reflex effects thus producing powerful muscle contractions. Glycine receptors in higher brain centres such as substantia nigra, neostriatum and hippocampus are commonly insensitive to strychnine, explaining why strychnine symptoms are largely spinal in origin. Clinical features:- If seeds are swallowed uncrushed, the hard pericarp resists digestion and seeds are passed in faeces without any poisonous symptoms. With crushed seeds, symptoms begin to appear within 15 to 30 minutes. Bitter taste in the mouth Sense of uneasiness, restlessness, fear and anxiety Increase difficulty in breathing and swallowing Muscle twitching and spasms of the muscle followed by convulsions. The convulsions are more marked in anti-gravity muscles and body arches in the hyperextension position and lie on the heel and head. This position of the body is known as opisthotonos. It is the most common position. However, at times, the body may bend forward and the condition is called emprosthotonos. If the body bends sidewise (i.e. lateral bending), the condition is called pleurothotonos. Contraction of the muscles of the face causes the widening of the angle of the mouth with creases appearing around the eyelids. This condition is known as risus sardonicus. Also called a sardonic smile due to grimacing that occurred due to muscle contraction of the face. There is difficulty in breathing during convulsions due to the contraction of the chest muscles and diaphragm. Complications:- Hypoxia Hyperthermia Rhabdomyolysis Metabolic acidosis/ lactic acidosis</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following tests for identifying blood stains is shown in the Image:", "options": [{"label": "A", "text": "Hemochromogen crystal test", "correct": false}, {"label": "B", "text": "Hemin crystal test", "correct": true}, {"label": "C", "text": "Leucomalachite green test", "correct": false}, {"label": "D", "text": "Luminol test", "correct": false}], "correct_answer": "B. Hemin crystal test", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891587332-QTDF003009IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hemin crystal test Teichmann test (Hemin crystal test): Stain extract and a few crystals of sodium chloride are taken and heated with glacial acetic acid. If the stain happened to be blood, dark brown rhomboid-shaped crystals will be formed as visible under the microscope.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A case of lead poisoning was admitted in the emergency. His blood sample was taken for analysis. Punctate basophilia in chronic lead poisoning is observed in the cytoplasm of:", "options": [{"label": "A", "text": "Neutrophil", "correct": false}, {"label": "B", "text": "Basophil", "correct": false}, {"label": "C", "text": "Lymphocytes", "correct": false}, {"label": "D", "text": "RBC", "correct": true}], "correct_answer": "D. RBC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>RBC Punctate basophilia or basophilic stippling means the presence of many dark blue-coloured pinhead-sized spots in the cytoplasm of red blood cells, due to the toxic action of lead on porphyrin metabolism.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A sample found at the crime site is mixed with NaOH, Pyridine and Glucose and the reaction generates the microscopic crystals shown in the image. The crystals are", "options": [{"label": "A", "text": "Hemin crystal", "correct": false}, {"label": "B", "text": "Sperm in picrate", "correct": false}, {"label": "C", "text": "Takayama crystals", "correct": true}, {"label": "D", "text": "Choline iodide crystals", "correct": false}], "correct_answer": "C. Takayama crystals", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891587451-QTDF003012IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Takayama crystals Haemochromogen Crystal Test (Takayama test) Place a small piece of suspected material on a glass slide and add 2 to 3 of Takayama reagent (sodium hydroxide. pyridine. glucose), and cover with a coverslip. Pink feathery crystals of haemo chromogen or reduced alkaline haematin arranged in clusters, sheaves, etc., appear in one to six minutes. Slight warming of the slide hastens the reaction. The result is negative if crystals are not formed in 30 minutes. The test gives good results even with old stains. It is delicate and more reliable</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 24-year-old male has come with burn injury all over his anterior trunk, and left lower extremity, including his perineum, genitalia, and right upper extremity. Calculate the Burn size?", "options": [{"label": "A", "text": "0.64", "correct": false}, {"label": "B", "text": "0.46", "correct": true}, {"label": "C", "text": "0.45", "correct": false}, {"label": "D", "text": "0.63", "correct": false}], "correct_answer": "B. 0.46", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>0.46 Determination of burn size estimates the extent of the injury . Burn size is generally assessed by the “Wallace rule of nines.” In adults, each upper extremity and the head and neck are 9% of the total body surface area (TBSA), the lower extremities and the anterior and posterior trunk are 18% each, and the perineum and genitalia are assumed to be 1% of the TBSA . Another method of estimating more minor burns is equating the area of the patient's open hand (including the palm and the extended fingers) with approximately 1% TBSA and then transposing that measurement visually onto the wound for a determination of its size. This method is crucial in evaluating burns of mixed distribution .</p>\n<p><strong>Highyeild:</strong></p><p>Wallace rule of nine</p>\n<p><strong>Extraedge:</strong></p><p>Wallace's rule of nines is contributed by Alfred Russel Wallace. To estimate minor burns: use the patient's open hand area (including palm and extended fingers). The open hand area is roughly 1% of the body surface area (TBSA).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 6 years old child came with burn injuries extending into her left leg, left arm, head, and neck. Estimate the burn size using the \"Rule of nines\":", "options": [{"label": "A", "text": "0.36", "correct": false}, {"label": "B", "text": "0.45", "correct": false}, {"label": "C", "text": "0.41", "correct": true}, {"label": "D", "text": "0.42", "correct": false}], "correct_answer": "C. 0.41", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>0.41 Children have a relatively large r portion of the body surface area in the head and neck , which is compensated for by a relatively smaller surface area in the lower extremities . Infants have 21% of the TBSA in the head and neck and 13% in each leg , incrementally approaching the adult proportions with increasing age. Child body Part-% of total BSA Arm - 9 % Head and neck- 18 % Leg- 14 % Anterior trunk- 18 % Posterior trunk- 18 %. Note: Berkow formula is used to determine burn size in children accurately.</p>\n<p><strong>Highyeild:</strong></p><p>table,tr,th,td {border:1px solid black;} Berkow formula to estimate burn size (%) based on area of burn in an isolated body part.* BODY PART 0-1 YEAR 1-4 YEARS 5-9 YEARS 10-14 YEARS 15-18 YEARS ADULT Head Neck Anterior trunk Posterior trunk Right buttock Left buttock Genitalia Right upper arm Left upper arm Right lower arm Left lower arm Right hand Left hand Right thigh Left thigh Right leg Left leg Right foot Left foot 19 2 13 13 2.5 2.5 1 4 4 3 3 2.5 2.5 5.5 5.5 5 5 3.5 3.5 17 2 13 13 2.5 2.5 1 4 4 3 3 25 2.5 6.5 6.5 5 5 3.5 3.5 13 2 13 13 2.5 25 1 4 4 3 3 25 25 8 8 5.5 5.5 3.5 3.5 11 2 13 13 2.5 2.5 1 4 4 3 3 2.5 2.5 8.5 8.5 6 6 3.5 3.5 9 2 13 13 2.5 2.5 1 4 4 3 3 2.5 2.5 9 9 6.5 6.5 3.5 3.5 7 2 13 13 2.5 2.5 1 4 4 3 3 2.5 2.5 9.5 9.5 7 7 3.5 3.5 *Estimates are made, recorded, and then summed to gain an accurate estimate of the body.</p>\n<p><strong>Extraedge:</strong></p><p>To assess the area of a burn, use the patient's hand as a guide for small burns. For larger burns, use the Lund and Browder chart. The ' rule of nines ' is only suitable for initial approximations.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "False about systemic effects of a severe burn is all Except", "options": [{"label": "A", "text": "Decreased gut permeability", "correct": true}, {"label": "B", "text": "Increased renal blood flow", "correct": false}, {"label": "C", "text": "Hypermetabolism", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "A. Decreased gut permeability", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Decreased gut permeability Severe burns covering more than 20% TBSA in adults and 40% TBSA in pediatric patients are typically followed by a period of stress, inflammation, and hypermetabolism, characterized by a hyperdynamic circulatory response with increased body temperature, glycolysis, proteolysis, lipolysis, and futile substrate cycling. Systemic effects of a severe burn: Vascular permeability and edema Immunosuppression Hypermetabolism Decreased renal blood flow Increased gut mucosal permeability Altered hemodynamics.</p>\n<p><strong>Extraedge:</strong></p><p>After the acute phase, the hypermetabolic phase occurs with high catecholamines, prostaglandins, glucagon, and cortisol levels. The hypermetabolic phase leads to pathophysiological changes .</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Warning signs of burns to the respiratory system is/are", "options": [{"label": "A", "text": "Burns around face & neck", "correct": false}, {"label": "B", "text": "Change in voice", "correct": false}, {"label": "C", "text": "Stridor", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above Respiratory system injuries usually occur if a person is trapped in a burning vehicle, house, car, or airplane and is forced to inhale the hot and poisonous gases. Warning signs of burns to the respiratory system : Burns around the face and neck A history of being trapped in a burning room Change in voice Stridor</p>\n<p><strong>Highyeild:</strong></p><p>Burns can cause severe harm to the airway and lungs, potentially leading to life-threatening outcomes. Inhalation of hot, smoke-filled air can result in three types of injury: upper airway injury, lower airway injury, and metabolic poisoning. Airway injuries are more likely when the face and neck are burned, and trapped in an enclosed space increases the risk.</p>\n<p><strong>Extraedge:</strong></p><p>Subcutaneous edema can occur with full-thickness burns, which can physically inhibit rib expansion. If a burn extending across the chest can compromise respiratory function.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The Topical agent used in the treatment of deep burns causing metabolic acidosis is", "options": [{"label": "A", "text": "Silver Sulphadiazine", "correct": false}, {"label": "B", "text": "Silver nitrate solution", "correct": false}, {"label": "C", "text": "Mafenide acetate", "correct": true}, {"label": "D", "text": "Cerium nitrate", "correct": false}], "correct_answer": "C. Mafenide acetate", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mafenide acetate The four most common dressings for full-thickness and contaminated wounds are Silver sulphadiazine cream (1%): This gives broad-spectrum prophylaxis against bacterial colonization and is particularly effective against Pseudomonas aeruginosa and methicillin-resistant Staphylococcus aureus. Silver nitrate solution (0.5%): Again, this is highly effective as prophylaxis against Pseudomonas colonization but not as active as silver sulphadiazine cream against some of the gram-negative aerobes. The other disadvantage of this solution is that it needs to be changed or the wounds resoaked every 2–4 hours . It also produces black staining on all the furniture surrounding the patient. Mafenide acetate cream: This is painful to apply. It is usually used as a 5% topical solution but has been associated with metabolic acidosis. Silver sulphadiazine and cerium nitrate: This is also a useful burn dressing, especially for full-thickness burns. It induces a sterile eschar on the burned skin to reduce some of the cell-mediated immunosuppression that occurs in burns. Cerium nitrate forms a sterile eschar and has also been shown to boost cell-mediated immunity in these patients.</p>\n<p><strong>Highyeild:</strong></p><p>Subcutaneous injection of a dilute adrenaline (epinephrine ) solution and tourniquet control blood loss during most burn injuries. Adrenaline solution is typically used at a dilution of 1:1,000,000 or 1:500,000 . The tumescence fluid used during the procedure is injected into the burn eschar and donor sites.</p>\n<p><strong>Extraedge:</strong></p><p>Staged burn excision involves shorter, more frequent surgical theatre trips. The remaining eschar must be managed/bound. Large excisions require an arterial line and central venous access for blood pressure monitoring. The anesthetist must control the acid-base balance, clotting time, and hemoglobin levels. The patient's core temperature should not drop below 36°C to avoid clotting irregularities.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which among the following is/are indications for referral to a burn centre?", "options": [{"label": "A", "text": "Electrical burns", "correct": false}, {"label": "B", "text": "Chemical burns", "correct": false}, {"label": "C", "text": "Inhalational injury", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above Guidelines for referral to a burn center: Partial - thickness burns >10% TBSA Burns involving the face, hands, feet, genitalia, perineum, or major joints Third-degree burns in any age group Electrical burns , including lightning injury Chemical burns Inhalation injury Burn injury in patients with complicated pre-existing medical disorders Patients with burns and concomitant trauma in which the burn is the greatest risk. If the trauma is the greater immediate risk, the patient may be stabilized in a trauma center before being transferred to a burn center. Burned children in hospitals without qualified personnel for the care of children Burn injury in patients who will require special social, emotional, or rehabilitative intervention .</p>\n<p><strong>Highyeild:</strong></p><p>Partial-thickness burns greater than 10% of TBSA require immediate medical attention. Burns involving sensitive areas such as the face, hands, feet, genitalia, perineum, or major joints require specialized care. Full-thickness burns to require urgent medical attention as they damage all skin and underlying tissue layers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The ideal temperature of water to cool the burnt area is", "options": [{"label": "A", "text": "10 degrees", "correct": false}, {"label": "B", "text": "15 degrees", "correct": true}, {"label": "C", "text": "20 degrees", "correct": false}, {"label": "D", "text": "25 degrees", "correct": false}], "correct_answer": "B. 15 degrees", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>15 degrees In temperate climates , cooling should be at about 15 ℃, and hypothermia is avoided. This provides analgesia and delays the microvascular damage in burns. It should occur for a minimum of 20 mins and is effective up to 1 hr after the burn injury particularly important in scalds.</p>\n<p><strong>Highyeild:</strong></p><p>Iced water should never be used on burns, regardless of their size. Using ice or cold water on larger burns can lead to systemic hypothermia, and vasoconstriction can worsen the burn.</p>\n<p><strong>Extraedge:</strong></p><p>Pouring room temperature water on a wound within 15 minutes of injury can reduce depth.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "All are advantages of tissue expansion except:", "options": [{"label": "A", "text": "Well vascularised tissue", "correct": false}, {"label": "B", "text": "Likely to be similar consistency", "correct": false}, {"label": "C", "text": "Good color match", "correct": false}, {"label": "D", "text": "Multiple expansion episodes", "correct": true}], "correct_answer": "D. Multiple expansion episodes", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Multiple expansion episodes Tissue expansion: This technique is valuable in using ‘local’ tissue for reconstruction . It involves placing a device – usually an expandable balloon constructed from silicone – beneath the tissue to be expanded and progressively enlarging the volume with fluid. In contrast, the overlying tissue accommodates the changed vascular pressure. The fluid (usually sterile saline) is introduced via a self-sealing port attached to a filling tube that enters the balloon. It may be introduced as frequently as can be tolerated by the patient until the tissues are stretched enough to be used for reconstruction. The tissues expanded do not hypertrophy, but there are major changes in the collagen structure. It must never be used under irradiated tissues (such as mastectomy sites), which will not expand but necrose.</p>\n<p><strong>Highyeild:</strong></p><p>Advantages and disadvantages of tissue expansion Advantages: Well-vascularized tissue. Tissue next to defect, so likely to be of similar consistency. Good color match Disadvantages: Multiple expansion episodes (sometimes painful) Cost of device High incidence of infection and extrusion (especially limbs)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Depth of electrical contact burn is", "options": [{"label": "A", "text": "Superficial epidermal", "correct": false}, {"label": "B", "text": "Superficial dermal", "correct": false}, {"label": "C", "text": "Deep dermal", "correct": false}, {"label": "D", "text": "Full thickness", "correct": true}], "correct_answer": "D. Full thickness", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Full thickness Causes of burns and their likely depth: Scald : Superficial , but with deep dermal patches in the absence of good first aid. Will be deep in a young infant Fat burns : Deep dermal Flame burns : Mixed deep dermal and full thickness Alkali burns, including cement: Often deep dermal or full thickness Acid burns : Weak concentrations superficial ; strong concentrations deep dermal Electrical contact burn: Full thickness .</p>\n<p><strong>Highyeild:</strong></p><p>The main risk of these injuries is the interference of alternating current with the heart's normal pacing, which can lead to cardiac arrest . Although the electricity does not typically cause major damage to the heart muscle, successful resuscitation should be long-lasting.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Deep second- degree burns involves: Epidermis Superficial dermis Deep dermis Subcutaneous fat Select the correct answer from given below code:", "options": [{"label": "A", "text": "1 only", "correct": false}, {"label": "B", "text": "1 & 2", "correct": false}, {"label": "C", "text": "1,2 & 3", "correct": true}, {"label": "D", "text": "1,2,3 & 4", "correct": false}], "correct_answer": "C. 1,2 & 3", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,2 & 3 Burn Classifications : First degree : injury localized to the epidermis Superficial second degree : injury to the epidermis and superficial dermis Deep second degree : injury through the epidermis and deep into the dermis Third degree : full-thickness injury through the epidermis and dermis into subcutaneous fat Fourth degree : injury through the skin and subcutaneous fat into underlying muscle or bone.</p>\n<p><strong>Highyeild:</strong></p><p>Classification of burn injuries</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Irreversibly injured zone of Burn injury is", "options": [{"label": "A", "text": "Zone of coagulation", "correct": true}, {"label": "B", "text": "Zone of hyperaemia", "correct": false}, {"label": "C", "text": "Zone of stasis", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "A. Zone of coagulation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Zone of coagulation The area of cutaneous or superficial injury has been divided into three zones : Zone of coagulation Zone of stasis Zone of hyperaemia. The necrotic area burds the zone of coagulation . This tissue is irreversibly damaged at the time of injury. The area immediately surrounding the necrotic zone has a moderate degree of insult with decreased tissue perfusion. This is termed the zone of stasis and, depending on the wound environment, can either survive or go on to coagulative necrosis. The zone of stasis is associated with vascular damage and vessel leakage. Thromboxane A2 , a potent vasoconstrictor, is present in high concentrations in burn wounds, and the local application of inhibitors improves blood flow and decreases the zone of stasis. Last area is the zone of hyperaemia , which is characterized by vasodilation from inflammation surrounding the burn wound. This region contains the clearly viable tissue from which the healing process begins and is generally not at risk for further necrosis.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Rolled edges are seen in", "options": [{"label": "A", "text": "Epithelioma", "correct": false}, {"label": "B", "text": "Syphilis", "correct": false}, {"label": "C", "text": "BCC", "correct": true}, {"label": "D", "text": "Tuberculosis", "correct": false}], "correct_answer": "C. BCC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>BCC An ulcer is a discontinuity of an epithelial surface . It is characterized by the destruction of the surface epithelium and a granulating base . Ulcers can be classified as non-specific, specific, and malignant.</p>\n<p><strong>Highyeild:</strong></p><p>Characteristic shapes of the edges of ulcers. Non-specific ulcer : shelving edge. Tuberculous ulcer : undermined edge. Basal cell carcinoma (rodent ulcer): rolled edge, which may exhibit small blood vessels. Epithelioma : heaped-up, everted edge, and irregular thickened base. Syphilis : punched-out edge and thin base, which may be covered with a ‘wash-leather’ slough.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option A. Epithelioma : heaped-up, everted edge, and irregular thickened base. Option B. Syphilis : punched-out edge and thin base, which may be covered with a ‘wash-leather’ slough. Option D. Tuberculosis : undermined edge.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 22 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Post-mortem lividity shown in the image is due to ………Poisoning", "options": [{"label": "A", "text": "Carbon monoxide", "correct": true}, {"label": "B", "text": "Hydrogen sulphide", "correct": false}, {"label": "C", "text": "Nitrites", "correct": false}, {"label": "D", "text": "Phosphorus", "correct": false}], "correct_answer": "A. Carbon monoxide", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893740291-QTDF067001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Carbon monoxide In a case of CO poisoning, the cherry-red colouration of the skin, mucous membranes, conjunctivae, nail beds, areas of hypostasis, blood, tissues and internal organs are seen in 15 to 20% of cases only. The cherry-red discolouration changes to dark green, then to brown with the onset of decomposition. The blood is fluid, hyperaemia is general and serous effusions are common.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Two friends were fighting as practice. However, as one punched the other over his neck, the other collapsed to the ground. Death following a ‘commando punch’ is due:", "options": [{"label": "A", "text": "Rupture of neck vessels", "correct": false}, {"label": "B", "text": "Suffocation", "correct": false}, {"label": "C", "text": "Reflex cardiac inhibition", "correct": true}, {"label": "D", "text": "Fracture dislocation of the cervical spine", "correct": false}], "correct_answer": "C. Reflex cardiac inhibition", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Reflex cardiac inhibition In \"commando punch\", the edge of the hand is brought forcibly across the side of the neck or the front of the larynx. Blows directly to the larynx, indirectly stimulates the sinus region, or the laryngeal sensory nerve endings and may trigger the cardio-inhibitory reflex.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was found unconscious in a burning building. He had no burns. Which of the following gas has systemic toxicity without irritation?", "options": [{"label": "A", "text": "Carbon dioxide", "correct": false}, {"label": "B", "text": "Phosphine", "correct": false}, {"label": "C", "text": "Carbon monoxide", "correct": true}, {"label": "D", "text": "Ammonia", "correct": false}], "correct_answer": "C. Carbon monoxide", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Carbon monoxide Carbon monoxide is a colourless, tasteless, non-irritative gas which is produced due to the incomplete combustion of carbon. Victims may not notice anything, except a headache, until they lapse into a coma and die. The effects of CO are simply those of suboxia. As most deaths are relatively rapid, blisters are rare.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 13 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Arun and Anvitha have lived separately for the past year after staying together for nine years. Their daughter, aged five years, is staying with her husband. On the pretext of making the daughter meet his wife, he comes to the wife's home and has sexual intercourse forcefully with the wife without her consent. Under Sec.376 B, what’s the minimum punishment for the husband?", "options": [{"label": "A", "text": "Not less than one year", "correct": false}, {"label": "B", "text": "Not less than two years", "correct": true}, {"label": "C", "text": "Not less than three years", "correct": false}, {"label": "D", "text": "Not less than four years", "correct": false}], "correct_answer": "B. Not less than two years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Not less than two years The punishment to the husband will not be less than two 376-B IPC Sexual intercourse by husband upon his wife during separation.- Whoever has sexual intercourse with his wife, who is living separately, whether under a decree of separation or otherwise, without her consent, shall be punished with imprisonment of either description for a term which shall not be less than two years but which may extend to seven years, and shall also be liable to fine?</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Since the punishment is at least two years, other Options of 1,3 and 4 years are irrelevant to this question.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A local newspaper publishes details about a gang rape victim. Due to a personal grudge between the owner of the newspaper agency and the victim’s father, they published the whole of the bio data of the victim, including her schooling, education, siblings and the exact location where she lived. Is the owner punishable according to?", "options": [{"label": "A", "text": "Sec 228 A IPC", "correct": true}, {"label": "B", "text": "Sec 100 IPC", "correct": false}, {"label": "C", "text": "Sec 294 IPC", "correct": false}, {"label": "D", "text": "Sec 326 A IPC", "correct": false}], "correct_answer": "A. Sec 228 A IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec 228 A IPC S.228-A, I.P.C.: Whoever prints or publishes the name or any matter which may make known the identity of the victim of rape (offences under S. 376 and 376A to E) shall be punished with imprisonment extending to two years.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. 100, I.P.C: “Seventhly-An act of throwing or administering acid or an attempt to throw or administer acid which may reasonably cause the apprehension that grievous hurt will otherwise be the consequence of such act\". In this, the right of private defence of the body extends to causing death. Option: C. 294, I.P.C.: Whoever, to the annoyance of others Does any obscene act in any public place or Sings, recites or utters any obscene song, Ballard or words in or near any public place shall be punished with imprisonment up to 3 months, or with a fine or with both Option: D. 326-A, I.P.C.: Voluntarily causing grievous hurt by use of acid, etc. Imprisonment of not less than ten years may extend to life and a fine of 10 lakh rupees.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Choose the incorrect statement.", "options": [{"label": "A", "text": "Male below the age of 18 years is considered to be incapable of committing rape", "correct": true}, {"label": "B", "text": "Females of any age may be victims of rape", "correct": false}, {"label": "C", "text": "A man can commit rape, and a woman cannot rape a man, although she may be guilty of an indecent assault upon him", "correct": false}, {"label": "D", "text": "According to Sec.114 A IEA, if the victim states in her evidence that she did not consent in a custodial situation or when she is a victim of gang rape, the court will consider she disagreed.", "correct": false}], "correct_answer": "A. Male below the age of 18 years is considered to be incapable of committing rape", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Male below the age of 18 years is considered to be incapable of committing rape Age of the Accused: In India, there is no age limit under which a boy is considered physically incapable of committing rape. The Court decides the question of his potency from the evidence in the case. Even old men save raped young girls.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Age of the Victim: No age is safe from rape, as children of one year or less and old women of 85 years have been raped. Children are more frequently raped than adults as they cannot offer much resistance, and also due to the false belief that venereal diseases are cured by sexual intercourse with a virgin. Option: C. Under the law, a man can only commit rape, and a woman cannot rape a man, although she may be guilty of an indecent assault upon him. Option: D. The burden of Proof: The prosecution must prove all the offence's elements. In many cases of rape, there are no signs of injury or intoxication by stupefying drugs, and the allegation of lack of consent is based on fear and fraud. According to S. 114-A I.E.A., if the victim states in her evidence before the Court that she did not consent, the Court shall presume that she did not agree in a custodial situation or when she is a victim of gang rape. The burden of proof of consent rests on the accused.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The police send a rape victim for a medical examination. However, the victim does not give consent for the examination. The doctor strips the victim naked. The victim registers a case against a doctor for stripping her naked despite not giving consent. What will be the punishment under Sec 354 IPC?", "options": [{"label": "A", "text": "One to 5 years imprisonment", "correct": false}, {"label": "B", "text": "One to 5 years imprisonment and fine", "correct": true}, {"label": "C", "text": "One to 10 years imprisonment", "correct": false}, {"label": "D", "text": "One to 10 years imprisonment and fine", "correct": false}], "correct_answer": "B. One to 5 years imprisonment and fine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>One to 5 years imprisonment and fine Stripping a naked female patient for medical examination is regarded as an assault. Such assaults are punishable under S. 354, I.P.C., up to one to 5 years imprisonment and a In such cases, a medical examination is of little value. Abrasions or bruises may sometimes be present due to the struggle. Since the punishment for this offence is up to five years and a fine, other Options are not relevant to this question. Hence are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Outrage of modesty of a woman is punishable under section:", "options": [{"label": "A", "text": "351 IPC", "correct": false}, {"label": "B", "text": "354 IPC", "correct": true}, {"label": "C", "text": "366 IPC", "correct": false}, {"label": "D", "text": "493 IPC", "correct": false}], "correct_answer": "B. 354 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>354 IPC 354, I.P.C.: Assault or use of criminal force to a woman intending to outrage her modesty (imprisonment of one year may extend to 5 years and fine). 354-A, I.P.C: Assault or use of criminal force to woman with intent to outrage her modesty (imprisonment of 1 year may extend to 5 years and fine). 354-A, I.P.C: Sexual harassment: Physical contact and advances involving sexual overtures, A demand or request for sexual flavours, Making sexually coloured remarks, Showing pornography and Imprisonment of 1 to 5 years or with fine or both. 354-B, I.P.C: Assault or use of criminal force to a woman or compelling her to be naked with intent to disrobe (imprisonment of not less than three years, may extend to 7 years and fine). 354-C, I.P.C: Voyeurism: Imprisonment of not less than one year; may extend to 3 years and fine; for second and subsequent offences, imprisonment of 3-7 years. 354D, I.P.C: Stalking: Whoever follows a woman and contacts or attempts to contact such woman fosters personal interaction repeatedly, despite a clear indication of disinterest by such woman, or monitors the use by a woman of the internet, e-mail or any other form of electronic communication (imprisonment up to 3 years and fine).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. IPC 351, 366, and 493 are not related to the outrage of the modesty of women. Hence there are better answers than these.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Sexual harassment is punishable under section:", "options": [{"label": "A", "text": "354 IPC", "correct": false}, {"label": "B", "text": "354 A IPC", "correct": true}, {"label": "C", "text": "354 C IPC", "correct": false}, {"label": "D", "text": "354 D IPC", "correct": false}], "correct_answer": "B. 354 A IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>354 A IPC 354-A, I.P.C: Assault or use of criminal force to woman with intent to outrage her modesty (imprisonment of 1 year may extend to 5 years and fine). 354-A, I.P.C: Sexual harassment: Physical contact and advances involving sexual overtures, A demand or request for sexual flavours, Making sexually coloured remarks, Showing pornography and Imprisonment of 1 to 5 years or with fine or both.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: 354, I.P.C.: Assault or use of criminal force to a woman intending to outrage her modesty (imprisonment of one year may extend to 5 years and fine). Option C: 354-C, I.P.C: Voyeurism: Imprisonment of not less than one year; may extend to 3 years and fine; for second and subsequent offences, imprisonment of 3-7 years. Option D: 354D, I.P.C: Stalking: Whoever follows a woman and contacts or attempts to contact such woman fosters personal interaction repeatedly, despite a clear indication of disinterest by such woman, or monitors the use by a woman of the internet, e-mail or any other form of electronic communication (imprisonment, upto three years and fine).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Stalking is punishable under section:", "options": [{"label": "A", "text": "354 IPC", "correct": false}, {"label": "B", "text": "354 A IPC", "correct": false}, {"label": "C", "text": "354 C IPC", "correct": false}, {"label": "D", "text": "354 D IPC", "correct": true}], "correct_answer": "D. 354 D IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>354 D IPC 354D, I.P.C : Stalking: Whoever follows a woman and contacts or attempts to contact such woman fosters personal interaction repeatedly, despite a clear indication of disinterest by such woman, or monitors the use by a woman of the internet, e-mail or any other form of electronic communication (imprisonment up to 3 years and fine).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: 354, I.P.C.: Assault or use of criminal force on a woman intending to outrage her modesty (imprisonment of one year may extend to 5 years and fine). Option B: 354-A, I.P.C: Assault or use of criminal force on a woman intending to outrage her modesty (imprisonment of 1 year may extend to 5 years and fine). 354-A, I.P.C: Sexual harassment: Physical contact and advances involving sexual overtures, A demand or request for sexual flavours, Making sexually coloured remarks, Showing pornography and Imprisonment of 1 to 5 years or with fine or both. Option C: 354-C, I.P.C: Voyeurism: Imprisonment of not less than one year; may extend to 3 years and fine; for second and subsequent offences, imprisonment of 3-7 years.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A man was held for raping a minor girl. The man said he could not penetrate before the public caught him. Legally a man will be guilty of rape when there are:", "options": [{"label": "A", "text": "Rupture of the hymen", "correct": false}, {"label": "B", "text": "Emission/ ejaculation of semen", "correct": false}, {"label": "C", "text": "Slightest penetration of penis within the vulva", "correct": true}, {"label": "D", "text": "Extensive injuries around the external genitalia", "correct": false}], "correct_answer": "C. Slightest penetration of penis within the vulva", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Slightest penetration of penis within the vulva A man is said to commit \"rape\" if he:- Penetrates his penis, to any extent, into the vagina, mouth, urethra or anus of a woman or makes her to do so with him or any other person; or Inserts, to any extent, any object or a part of the body, not being the penis, into the vagina, the urethra or anus of a woman or makes her to do so with him or any other person; or Manipulates any part of the body of a woman to cause penetration into the vagina, urethra, anus or any part of the body of such woman or makes her do so with him or any other person; or Applies his mouth to the vagina, anus, or urethra of a woman or makes her do so with him or any other person.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B & D. It is not necessary that the accused has to rupture the hymen or ejaculate in the victim or cause extensive injuries. The slightest penetration of the penis or any other object is enough to be punished under the law.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which one of the following statements regarding rape is false?", "options": [{"label": "A", "text": "An impotent person can commit rape", "correct": false}, {"label": "B", "text": "Husband can’t be held guilty of rape for having sexual intercourse with his wife, irrespective of her age", "correct": true}, {"label": "C", "text": "A twelve-year-old boy can be charged with rape", "correct": false}, {"label": "D", "text": "Punishment for committing rape is given under section 376 IPC", "correct": false}], "correct_answer": "B. Husband can’t be held guilty of rape for having sexual intercourse with his wife, irrespective of her age", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Husband can’t be held guilty of rape for having sexual intercourse with his wife, irrespective of her age A husband can be held guilty of rape even if it is his wife if she does not give consent of her own will or is less than 18 years of age. Consent is not valid for sexual intercourse in the following circumstances: When it is obtained by fraud, such as by impersonation of the husband or misrepresenting When it is obtained by putting her or any person in whom she is interested in fear of death or hurt.\\ When obtained from a woman who is of unsound mind or in a drunken state. When the woman is below 18 years of age, even if the woman is his wife</p>\n<p><strong>Random:</strong></p><p>Explanation for Incorrect Options:- Option: A, C & D. These statements are all true.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Under section 376, IPC minimum punishment for committing rape is _ years’ imprisonment:", "options": [{"label": "A", "text": "5", "correct": false}, {"label": "B", "text": "7", "correct": false}, {"label": "C", "text": "10", "correct": true}, {"label": "D", "text": "12", "correct": false}], "correct_answer": "C. 10", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>10 According to 376 IPC, whoever commits rape shall be punished with rigorous imprisonment of either –description for a term which shall not be less than ten years. But which may extend to imprisonment for life, and shall also be liable to fine.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. Since the answer to this question is at least ten years, other Options of 5,7 and 12 years are irrelevant. Hence these Options are different from the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The minimum punishment for committing gang rape:", "options": [{"label": "A", "text": "Rigorous imprisonment for seven years", "correct": false}, {"label": "B", "text": "Rigorous imprisonment for ten years", "correct": false}, {"label": "C", "text": "Rigorous imprisonment for 14 years", "correct": false}, {"label": "D", "text": "Rigorous imprisonment for 20 years", "correct": true}], "correct_answer": "D. Rigorous imprisonment for 20 years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Rigorous imprisonment for 20 years Where a woman is raped by one or more persons constituting a group or acting in furtherance of a common intention, each of those persons shall be deemed to have committed the offence of rape and shall be punished with rigorous imprisonment for a term which shall not be less than twenty years, but which may extend to life which shall mean imprisonment for the remainder of that person's natural life, and with fine.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C. Since the answer to this question is 20 years, other Options of seven, ten and fourteen years are not relevant to this question. Hence these Options are different from the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The gynaecological resident was getting ready to examine a rape victim. She was advised to look for injuries over the genitalia, especially over the hymen. The common position of hymen tears in a virgin upon primary sexual intercourse:", "options": [{"label": "A", "text": "3 O’clock position", "correct": false}, {"label": "B", "text": "7 o’clock position", "correct": true}, {"label": "C", "text": "10 o’clock position", "correct": false}, {"label": "D", "text": "12 o’clock position", "correct": false}], "correct_answer": "B. 7 o’clock position", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>7 o’clock position In the case of a virgin, tearing usually occurs posteriorly at the sides, between 5 and 7 '0 clock position, but most frequently in the middle line of the hymen. Tears usually occur in the posterior midline of the hymen because the hymen lies suspended across a potential space, whereas anteriorly, the periurethral tissues buttress the hymen. More than two tears are unusual. Several hymenal lacerations indicate first sexual intercourse.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D. Since the answer is 7'O clock position, other Options are irrelevant to this question. Hence are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Disclosure of the name of a rape victim is punishable under section:", "options": [{"label": "A", "text": "354 IPC", "correct": false}, {"label": "B", "text": "497 IPC", "correct": false}, {"label": "C", "text": "228A IPC", "correct": true}, {"label": "D", "text": "376 IPC", "correct": false}], "correct_answer": "C. 228A IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>228A IPC 228-A, I.P.C .: Whoever prints or publishes the name or any matter which may make known the identity of the victim of rape (offences under S. 376 and 376A to E) shall be punished with imprisonment extending to two years.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: 354, I.P.C.: Assault or use of criminal force to a woman intending to outrage her modesty (imprisonment of one year may extend to 5 years and fine). Option B: 497, IPC:-The donor and recipient cannot be held guilty of adultery in India, as S. 497, I.P.C. requires sexual intercourse as a necessary part of adultery. Adultery is punishable by imprisonment for up to five years. Option D: 376, IPC:-related to rape.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Florence's test is positive due to the presence of the following:", "options": [{"label": "A", "text": "Citric acid", "correct": false}, {"label": "B", "text": "Choline", "correct": true}, {"label": "C", "text": "Spermine", "correct": false}, {"label": "D", "text": "Prostaglandin", "correct": false}], "correct_answer": "B. Choline", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Choline Florence Test: The stain is extracted by 10 per cent hydrochloric acid, and a drop is placed on a glass slide and allowed to dry. A coverslip is placed over this, and a drop of Florence solution (potassium iodide, iodine, and water) can run under the coverslip. If semen is present, dark-brown crystals of choline iodide appear immediately. They are rhombic or needle-shaped crystals resembling haemin but are more significant and arranged in clusters, rosettes, crosses, etc. Choline originates from the seminal vesicles. The test is not proof of seminal fluid, but only of the presence of some vegetable or animal substance. A negative reaction is proof that the stain is not seminal.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect options:- Option: A, C & D. Citric acid, spermine and prostaglandin are not the relevant products in the Florence Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A dried stain extract, when added to an alcoholic solution of picric acid, develops into yellow, long, needle-shaped crystals. The stain extract is of", "options": [{"label": "A", "text": "Blood", "correct": false}, {"label": "B", "text": "Urine", "correct": false}, {"label": "C", "text": "Semen", "correct": true}, {"label": "D", "text": "Bile", "correct": false}], "correct_answer": "C. Semen", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Semen Barberio's Test: A saturated aqueous or alcoholic solution of picric acid when added to the spermatic fluid, produces yellow needle-shaped rhombic crystals of spermine picrate. The reaction probably depends on the presence of prostatic secretion.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. Blood, Urine and Bile are irrelevant in Barberio's Test. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Barberio’s test is positive due to the presence of:", "options": [{"label": "A", "text": "Citric acid", "correct": false}, {"label": "B", "text": "Choline", "correct": false}, {"label": "C", "text": "Spermine", "correct": true}, {"label": "D", "text": "Prostaglandin", "correct": false}], "correct_answer": "C. Spermine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Spermine Barberio's Test: A saturated aqueous or alcoholic solution of picric acid, when added to spermatic fluid, produces yellow needle-shaped rhombic crystals of spermine picrate. The reaction probably depends on the presence of prostatic secretion.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. Citric acid, choline and prostaglandin are not the relevant products in Barberio's test. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An accused was brought under the allegation of sexual assault. But he denies it, as he underwent a vasectomy a year ago. The confirmatory test for the presence of seminal stain in case of a person suffering from azoospermia:", "options": [{"label": "A", "text": "Florence test", "correct": false}, {"label": "B", "text": "Creatine phosphokinase test", "correct": false}, {"label": "C", "text": "Acid phosphatase test", "correct": true}, {"label": "D", "text": "Demonstration of spermatozoa", "correct": false}], "correct_answer": "C. Acid phosphatase test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Acid phosphatase test Is conclusive in the absence of demonstrable sperms or aspermia.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:-- Option: D . Tests used for detection of semen - Barberio’s test Florence test Option: A. Acid phosphate test. Option: B. Creatine kinase test Immunological test Choline and spermine test.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Sexual intercourse with one’s wife amounts to rape if she is less than", "options": [{"label": "A", "text": "18 Years", "correct": true}, {"label": "B", "text": "16 Years", "correct": false}, {"label": "C", "text": "15 Years", "correct": false}, {"label": "D", "text": "12 Years", "correct": false}], "correct_answer": "A. 18 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>18 Years Sexual intercourse or sexual acts by a man with his wife. The wife being under eighteen years of age is rape. A husband cannot be guilty of rape on his wife if she is above eighteen years because, in marriage, the wife consents to the husband's exercising the marital right of intercourse during the continuation of legal marriage. This age bracket was raised from 15 years to 18 years by the supreme</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C & D. 16, 12 and 15 years are not relevant to this question of marital rape. Hence these Options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A court has ordered a separation of 6 months for a couple who have filed for divorce. The husband has sexual intercourse with his wife without her consent. He can be punished under", "options": [{"label": "A", "text": "Ipc 376", "correct": false}, {"label": "B", "text": "Ipc 376 B", "correct": true}, {"label": "C", "text": "Ipc 376 D", "correct": false}, {"label": "D", "text": "Cant be punished as divorce has not happened yet", "correct": false}], "correct_answer": "B. Ipc 376 B", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ipc 376 B Section 376B. I.P.C: Whoever has sexual intercourse with his wife. who is living separately, whether under a decree of separation or otherwise, without her consent shall be punished with imprisonment of either description for a term which shall not be less than two years but may extend to seven years and shall also be liable to fine?</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: 376 I.P.C: (1) Whoever, except in the cases provided for in the sub-section, commits rape is to be punished with rigorous imprisonment of either a description for a term which shall not be less than seven years but which may extend upto imprisonment for life and shall also be liable to fine. Option C: S 376D, I.P.C: Where a woman is raped by one or more persons constituting a group or acting in furtherance of a common intention, each of those persons shall be deemed to have committed the offence of rape and shall be punished with rigorous imprisonment for a term which shall not be less than twenty years, but which may extend to life which shall mean imprisonment for the remainder of that person's natural life, and with fine.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "True statement are all except-", "options": [{"label": "A", "text": "Sec 376A IPC is marital rape", "correct": true}, {"label": "B", "text": "In camera trial is done for rape", "correct": false}, {"label": "C", "text": "IPC 228A is punishment for victim identification in media in rape case", "correct": false}, {"label": "D", "text": "Punishment for gang rape can be given to a female", "correct": false}], "correct_answer": "A. Sec 376A IPC is marital rape", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec 376A IPC is marital rape S 376A, I.P.C: Whoever, commits an offence punishable under sub-section or sub-section of section 376 and in the course of such commission inflicts an injury which causes the death of the woman or causes the woman to be in a persistent vegetative state shall be punished with rigorous imprisonment for a term which shall not be less than twenty years, but which may extend to imprisonment for life, which shall mean imprisonment for the remainder of that per ones natural life, or with death</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B,C & D. All the other statements given in the question are true.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 30 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The presence of marbling on a dead body suggests time since the death of:", "options": [{"label": "A", "text": "12 to 24 hours", "correct": false}, {"label": "B", "text": "24 to 36 hours", "correct": false}, {"label": "C", "text": "36 to 48 hours", "correct": true}, {"label": "D", "text": "48 to 72 hours", "correct": false}], "correct_answer": "C. 36 to 48 hours", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>36 to 48 hours Marbling starts in 24 hours but is prominent in 36 to 48 hours.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, B & D: Since marbling is prominent in 36 to 48 hours, other Options are not significant to this question. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In which poisoning putrefaction is delayed?", "options": [{"label": "A", "text": "Oxalic acid", "correct": false}, {"label": "B", "text": "Organophosphorous poisoning", "correct": false}, {"label": "C", "text": "Aluminum phosphate poisoning", "correct": false}, {"label": "D", "text": "Carbolic acid poisoning", "correct": true}], "correct_answer": "D. Carbolic acid poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Carbolic acid poisoning Putrefaction is delayed after death due to wasting diseases, anaemia, severe haemorrhage, debility, poisoning by carbolic acid, zinc chloride, strychnine and chronic heavy metal poisoning, due to the preservative action of such substances on the tissues or their destructive or inhibitive action on organisms, which influence decomposition.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A, B & C . Oxalic acid, organophosphorus poisoning and aluminium phosphate poisoning do not delay putrefaction. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Postmortem Haemolysis occurs due to bacterial enzymes:", "options": [{"label": "A", "text": "Phospholipase", "correct": false}, {"label": "B", "text": "Hyaluronidase", "correct": false}, {"label": "C", "text": "Streptokinase", "correct": false}, {"label": "D", "text": "Lecithinase", "correct": true}], "correct_answer": "D. Lecithinase", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lecithinase Lecithinase produced by welchii is most important in putrefaction. This hydrolyses the lecithin which is present in all cell membranes including blood cells·, and is responsible for the post-mortem haemolysis of blood.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A, B & C . Phospholipase, hyaluronidase and streptokinase do not cause Hemolysis in Postmortem bodies. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Kevorkian Sign is an indicator of", "options": [{"label": "A", "text": "Burn injuries to the face", "correct": false}, {"label": "B", "text": "Ante-mortem hanging", "correct": false}, {"label": "C", "text": "Early postmortem change", "correct": true}, {"label": "D", "text": "Decomposition", "correct": false}], "correct_answer": "C. Early postmortem change", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Early postmortem change Fragmentation or segmentation (tuking or shunting) of the blood columns (Kevorkian sign) in the retinal vessels appear within minutes after death and persists for about an hour. This occurs all over the body due to loss of blood pressure but it can be seen only in the retina by ophthalmoscope. The retina is pale for the first two hours. At about six hours, the disk outline is hazy and becomes blurred in 7 to 10 hours. These changes are of little practical value.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D . Kervokian Sign is not related to burn injuries to the face, ante- mortem hanging or decomposition. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Differences between postmortem staining and contusion are all, except", "options": [{"label": "A", "text": "Bluish in colour", "correct": false}, {"label": "B", "text": "Disappear on pressure", "correct": false}, {"label": "C", "text": "Margins are regular", "correct": false}, {"label": "D", "text": "Extravasation is found", "correct": true}], "correct_answer": "D. Extravasation is found", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Extravasation is found Differences between P.M. Staining and Bruise Traits Post-mortem staining Bruise 1. Causes Due to the dilatation of blood vessels in the dermis Due to rupture of blood vessels 2. Site Seen on Dependent parts of the body Anywhere on the body 3. Appearance No elevation of the involved area Swollen due to extravasated blood and oedema 4. Epidermis Not Abraded Maybe abraded 5. Margins Clearly defined Merge with the surrounding area 6. Colour Uniform bluish purple in colour Colour changes with the age of the injury 7. On Incision Blood is seen in blood vessels, which can be easily washed away Extravasated and clotted Blood is seen in surrounding tissues, but it cannot be washed away easily 8. Effect of pressure Absent Little lighter over the area of pressure</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The enzyme responsible for postmortem hemolysis is?", "options": [{"label": "A", "text": "Hemolysin", "correct": false}, {"label": "B", "text": "Lecithinase", "correct": true}, {"label": "C", "text": "Lipo proteinase", "correct": false}, {"label": "D", "text": "Protease", "correct": false}], "correct_answer": "B. Lecithinase", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lecithinase Lecithinase produced by Cl. welchii is the most important. This hydrolyses the lecithin which is present in all cell membranes including blood cells·, and is responsible for the postmortem haemolysis of blood. The other organisms include Streptococci, Staphylococci, Bacteroides, anaerobic lactobacilli, diphtheroid, B. proteus, E. coli., B. aerogenes capsulatus , etc.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D . Hemolysin, Lipoproteinase and protease are not responsible for postmortem hemolysis. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The method of identification using the imprint shown in the Illustration is", "options": [{"label": "A", "text": "Dactylography", "correct": false}, {"label": "B", "text": "Podogram", "correct": false}, {"label": "C", "text": "Cheiloscopy", "correct": true}, {"label": "D", "text": "Poroscopy", "correct": false}], "correct_answer": "C. Cheiloscopy", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893175764-QTDF052007IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cheiloscopy The fissures and grooves on the lips are claimed to be characteristic of the individual. Lip prints are divided into six patterns which are specific to the individual; vertical, branched, intersected, reticular patterns, etc. 24 characteristic details have been identified. Identification is established if 7 to 9 characteristics tally. Minor differences can be noted between the right and the left and upper and lower lips. Lip prints are seen on crockery, cloth, paper, window panes, cigarette ends, etc.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . Dactylography- the study of fingerprints Option: B . Podogram- the study of footprints Option: D . Poroscopy- the study of ridges on fingers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Paltauf’s hemorrhage occur at:", "options": [{"label": "A", "text": "Subconjunctiva", "correct": false}, {"label": "B", "text": "Sublingual region", "correct": false}, {"label": "C", "text": "Subpleural region", "correct": true}, {"label": "D", "text": "Epicardial region", "correct": false}], "correct_answer": "C. Subpleural region", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Subpleural region Paltaufs haemorrhages are shining, pale pink or bluish-red, and may be minute or 3 to 5 cm. in diameter. They are usually present in about 50 per cent of cases in the lower lobes of the lungs but may be seen on the anterior surfaces of the lungs, and the interlobar surfaces. Red and grey patches may be seen on the surface, due to Paltaufs haemorrhages and patchy interstitial emphysema respectively</p>\n<p><strong>Random:</strong></p><p>Explanation For incorrect options:- Option: A, B & D . Paltaufs haemorrhages are not related to the subconjunctival, sublingual or epicardial region. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A doctor performing an autopsy finds the below-shown image on an ophthalmoscopic examination of the eye. This finding is seen after how many hours since the death?", "options": [{"label": "A", "text": "2 hours", "correct": false}, {"label": "B", "text": "3 hours", "correct": false}, {"label": "C", "text": "1 hour", "correct": true}, {"label": "D", "text": "12 hours", "correct": false}], "correct_answer": "C. 1 hour", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893175949-QTDF052009IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1 hour Fragmentation or segmentation of the blood columns- K evorkian sign , in the retinal vessels, appear within minutes after death, and persists for about an hour.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A- The eye change that appears at 2 hours is a reduction in intra-ocular tension. Option B- The eye change that appears at 3 hours is tache noir Option D- No particular eye changes occur at 12 hours</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A resident was called to examine elderly women at an old age home in Ghaziabad. The doctor saw the woman lying in bed motionless, quickly checked the women's heartbeat and pulse and declared her dead. In the autopsy room, while the body was being placed on the table, the doctor heard a gurgling sound and noticed a slight swallowing movement. What should the doctor do next?", "options": [{"label": "A", "text": "Declare the lady dead and hand over the body to relatives", "correct": false}, {"label": "B", "text": "Take her to the hospital as she is in suspended animation", "correct": true}, {"label": "C", "text": "Start CPR", "correct": false}, {"label": "D", "text": "Leave the lady there as she will be fine in a few minutes.", "correct": false}], "correct_answer": "B. Take her to the hospital as she is in suspended animation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Take her to the hospital as she is in suspended animation Is correct because the lady is in suspended animation and she needs urgent care in the SUSPENDED ANIMATION (apparent death): In this condition signs of life are not found, as the functions are interrupted for some time, or are reduced to a However, life continues and resuscitation is successful in such cases. The metabolic rate is so reduced that the requirement of the individual cell for oxygen is satisfied through the use of oxygen dissolved in the body fluids. In freezing of the body, or in severe drug poisoning of the brain, the activity of the brain can completely stop and in some cases start again. Suspended animation may be produced voluntarily. Practitioners of yoga can pass into a trance, death-like in character. Involuntary suspension of animation lasting from a few seconds to half an hour or more may be found in vagal inhibition, severe syncopal attacks, newborn infants, drowning, electrocution, sunstroke, cholera, narcotic poisoning, after anaesthesia, shock, hypothermia, cerebral concussion, insanity, etc. The patient can be resuscitated by cardiac massage or electric stimulator and artificial respiration.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D . Since the patient is in suspended animation, she should be taken to the hospital as the patient is alive and never to be declared dead or left alone. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A man aged 93 years was heavily drugged last night. He was declared dead and was taken to the hospital mortuary. His family had come and started crying. His son also arrived, but he was surprised to see his father seated on top of the table and complaining of a mild headache. He subsequently walked home. What should be the probable condition?", "options": [{"label": "A", "text": "Miracle", "correct": false}, {"label": "B", "text": "Suspended animation", "correct": true}, {"label": "C", "text": "Sudden cardiac arrest", "correct": false}, {"label": "D", "text": "Insanity", "correct": false}], "correct_answer": "B. Suspended animation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Suspended animation The patient was in suspended animation. SUSPENDED ANIMATION (apparent death): In this condition signs of life are not found, as the functions are interrupted for some time, or are reduced to a However, life continues and resuscitation is successful in such cases. The metabolic rate is so reduced that the requirement of the individual cell for oxygen is satisfied through the use of oxygen dissolved in the body fluids. In freezing the body, or in severe drug poisoning of the brain, the activity of the brain can completely stop and in some cases start again. Suspended animation may be produced voluntarily. Practitioners of yoga can pass into a trance, death-like in character. Involuntary suspension of animation lasting from a few seconds to half an hour or more may be found in vagal inhibition, severe syncopal attacks, newborn infants, drowning, electrocution, sunstroke, cholera, narcotic poisoning, after anaesthesia, shock, hypothermia, cerebral concussion, insanity, etc. The patient can be resuscitated by cardiac massage or electric stimulator and artificial respiration.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. The above patient was in suspended animation as he was heavily drugged the previous night. The symptoms and history don't relate to a miracle, sudden cardiac arrest or even insanity. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following statement is correct:- Putrefaction begins above 10°C and is optimum between 21 °C and 38°C For putrefaction moisture is necessary, and rapid drying of the body inhibits it. Free access to air inhibits putrefaction. Initially clothing hastens putrefaction by maintaining body temperature above that at which putrefactive organisms multiply for a longer period. Select the correct answer from given below code:", "options": [{"label": "A", "text": "A B C and D", "correct": false}, {"label": "B", "text": "A B and C", "correct": false}, {"label": "C", "text": "A B and D", "correct": true}, {"label": "D", "text": "A and B", "correct": false}], "correct_answer": "C. A B and D", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A B and D Only point C is wrong as free access to air hastens putrefaction. CONDITIONS AFFECTING THE RATE OF PUTREFACTION: (A) EXTERNAL: TEMPERATURE: Putrefaction begins above 10°C and is optimum between 21 °C and 38°C. A temperature increase of 10°C usually doubles the rate of most chemical processes and reactions. It is arrested below 0°C. and above 48°C. The rate of decomposition is about twice as rapid in summer as in winter. Advanced putrefaction may be seen within 24 to 36 hours in summer. Differences in temperature can cause varying areas in the same body to show different rates of decomposition. Pillows put over and under the deceased's head prevent the circulation of air and cause much more decomposition in the face than is seen in other parts of the body. A frozen body will not undergo decomposition until it defrosts. If decomposition has already set in, refrigeration of the body may not stop decomposition completely. Option: B. MOISTURE: For putrefaction moisture is necessary, and rapid drying of the body practically inhibit If the organic substance is dried, putrefaction is arrested. After death from general anasarca, putrefaction is very rapid, and bodies recovered from the water, if left in the air decompose rapidly. Organs which contain water decompose more readily than dry ones. Option: C. AIR: Free access to air hastens putrefaction, partly because the air conveys organisms to the body. In normal conditions, the unbroken skin acts as an impermeable barrier to bacteria. Moist and still air helps putrefaction. Option: D. CLOTHING: Initially, clothing hastens putrefaction by maintaining body temperature above that at which putrefactive organisms multiply for a longer period. If the clothing is tight as under the belts. In Suspenders, socks, tight-fitting undergarments, and boots, the putrefaction is slow, for it causes compression of the tissues, which drives out the blood from the part, and prevents the entry of internal organisms. Clothes prevent the access of airborne organisms, flies, insects. etc., which destroy the tissues. MANNER OF BURIAL: If the body is buried soon after death, putrefaction is less. Putrefaction is delayed if the body is buried in dry, sandy soil, or a grave deeper than two metres, and when the body is covered and placed in a coffin because of the exclusion of water, air and action of insects and animals. When a body is buried in lime, decomposition is delayed. Putrefaction is rapid in a body buried in a damp, marshy or shallow grave without clothes or a coffin because the body is exposed to constant changes in Putrefaction is more rapid in porous sandy soil than in soils with an excess of clay. Putrefaction is more rapid if changes in decomposition are already present at the time of burial. In acid-peaty soils, even the bones may be destroyed. When the bodies are buried in a common grave without coffins, those bodies lying in the centre of the grave may be better preserved.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Knowledge of the signs of death help to differentiate death from suspended animation. The changes which take place may be helpful in the estimation of the approximate time of death. Which of the following is not an immediate change of death?", "options": [{"label": "A", "text": "Insensibility and loss of voluntary power.", "correct": false}, {"label": "B", "text": "Cessation of respiration.", "correct": false}, {"label": "C", "text": "Cessation of circulation.", "correct": false}, {"label": "D", "text": "Pallor and loss of elasticity of the skin", "correct": true}], "correct_answer": "D. Pallor and loss of elasticity of the skin", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pallor and loss of elasticity of the skin Pallor and elasticity loss is an early cellular death (and not an immediate cause). Changes after death: Immediate (somatic death). Pallor and loss of elasticity of the skin Changes in the eye. Primary flaccidity of muscles. Cooling of the body. Postmortem lividity. Rigor mortis. Late (decomposition and decay). Putrefaction. Adipocere formation. Mummification.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Insensibility and loss of voluntary power. Option: B. Cessation of respiration. Option: C. Cessation of circulation. Early (cellular death)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Knowledge of the signs of death help to differentiate death from suspended animation. The changes which take place may be helpful in the estimation of the approximate time of death. Which of the following is not an early change of death?", "options": [{"label": "A", "text": "Pallor and loss of elasticity of the skin", "correct": false}, {"label": "B", "text": "Change in the eye.", "correct": false}, {"label": "C", "text": "Primary flaccidity of muscles.", "correct": false}, {"label": "D", "text": "Putrefaction", "correct": true}], "correct_answer": "D. Putrefaction", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Putrefaction Adipocere formation. Mummification. Changes after death: Immediate (somatic death). Insensibility and loss of voluntary power. Cessation of respiration. Cessation of circulation. Early (cellular death)</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Pallor and loss of elasticity of the skin. Option: B. Changes in the eye. Option: C. Primary flaccidity of muscles. Cooling of the body. Postmortem lividity. Rigor mortis. Late (decomposition and decay).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The condition in which signs of life are not found, as the functions are interrupted for some time, or are reduced to a minimum is called?", "options": [{"label": "A", "text": "Forensic taphonomy", "correct": false}, {"label": "B", "text": "Postmortem lividity", "correct": false}, {"label": "C", "text": "Suspended animation", "correct": true}, {"label": "D", "text": "Algor mortis", "correct": false}], "correct_answer": "C. Suspended animation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Suspended animation SUSPENDED ANIMATION (apparent death) In this condition signs of life are not found, as the functions are interrupted for some time, or are reduced to a However, life continues and resuscitation is successful in such cases. The metabolic rate is so reduced that the requirement of the individual cell for oxygen is satisfied through the use of oxygen dissolved in the body fluids. In freezing the body, or in severe drug poisoning of the brain the activity of the brain can completely stop and in some cases start again. Suspended animation may be produced voluntarily. Practitioners of yoga can pass into a trance, death-like in character. Involuntary suspension of animation lasting from a few seconds to half an hour or more may be found in vagal inhibition, severe syncopal attacks, newborn infants, drowning, electrocution, sunstroke, cholera, narcotic poisoning, after anaesthesia, shock, hypothermia, cerebral concussion, insanity, etc. The patient can be resuscitated by cardiac massage or electric stimulator and artificial respiration.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . Forensic taphonomy is the interdisciplinary study and interpretation of postmortem processes of human remains in the dispositional context, i.e., the history of changes in a body following the death Option: B . Lividity: This is the bluish-purple or purplish-red (due to deoxyhaemoglobin) discolouration, which appears under the skin in the most superficial layers of the dermis (rete mucosum) of the dependent parts of the body after death, due to capillo-venous distention. It is also called postmortem staining, subcutaneous hypostasis, livor mortis, cadaveric lividity, suggillations, vibices and darkening of death. Option : D. Algor mortis: The cooling of the body ('chill of death') after death is a complex process, which does not occur at the same rate throughout the body.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 25 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 25-year-old girl was admitted with cholecystectomy. The surgeon proceeded with the surgery with her written consent. The minimum age required to give consent for surgery is:", "options": [{"label": "A", "text": "12 Years", "correct": false}, {"label": "B", "text": "16 Years", "correct": false}, {"label": "C", "text": "18 Years", "correct": true}, {"label": "D", "text": "21 Years", "correct": false}], "correct_answer": "C. 18 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>18 Years A person above 18 can give valid consent to suffer any harm resulting from an act not intended or not known to cause death or grievous hurt.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. 12 and 16 years are considered adolescents, not 21 years is way above the cut-off for consent. Hence these options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An accused person can petition the magistrate for his medical examination under which CrPC?", "options": [{"label": "A", "text": "53", "correct": false}, {"label": "B", "text": "54", "correct": true}, {"label": "C", "text": "82", "correct": false}, {"label": "D", "text": "84", "correct": false}], "correct_answer": "B. 54", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>54 54, Cr.P.C. An arrested person, at his request, may be examined by a doctor to detect evidence in his favour. A copy of the report of such examination is to be furnished by the medical practitioner to the arrested person or the person nominated by the such arrested person.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. CrPC 53, CrPC 82 and CrPC 84 are unrelated to the accused person petitioning for his medical examination. Hence those three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A prisoner eats a large number of carrots to simulate jaundice. What is the term used to describe such behaviour?", "options": [{"label": "A", "text": "Malingering", "correct": true}, {"label": "B", "text": "Factitious disorder", "correct": false}, {"label": "C", "text": "Munchausen's syndrome", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "A. Malingering", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Malingering Malingering or shamming means conscious, planned feigning or pretending a disease for gain. Diseases may be feigned for several reasons, such as by soldiers or policemen to avoid their duties, by prisoners to avoid hard work, by businessmen to avoid business contracts, by workmen to claim compensation, by beggars to attract public sympathy, by criminals to avoid legal responsibility, etc. Patients can distort or exaggerate their symptoms, but true simulation is rare. The patient may injure his nasopharynx with a sharp instrument, swallow the blood and regurgitate it in front of the doctor to mimic hematemesis. A skilful puncturing of the anal or vaginal mucosa may produce bleeding. Excessive intake of digitalis may simulate a heart condition. Eating a large number of carrots will produce carotenemia and may simulate jaundice. Chronic ingestion of coumarin will induce a haemorrhagic diathesis</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Factitious disorder is a serious mental disorder in which someone deceives others by appearing sick, purposely getting sick, or self-injury. The factitious disorder can also happen when family members or caregivers falsely present others, such as children, as ill, injured, or impaired. Option: C. Munchausen's syndrome is a psychological disorder where someone pretends to be ill or deliberately produces symptoms of illness in themselves. Their main intention is to assume the \"sick role\" so that people care for them and they are the centre of attention.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In a comatose patient, when life-sustaining measures are withdrawn, the procedure is as follows:", "options": [{"label": "A", "text": "Active euthanasia", "correct": false}, {"label": "B", "text": "Passive euthanasia", "correct": true}, {"label": "C", "text": "Involuntary euthanasia", "correct": false}, {"label": "D", "text": "Voluntary euthanasia", "correct": false}], "correct_answer": "B. Passive euthanasia", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Passive euthanasia Passive euthanasia means discontinuing or not using extraordinary life-sustaining measures to prolong life. This includes acts of omission, such as failure to resuscitate a terminally ill or hopelessly incapacitated patient or a severely defective newborn It is not using measures that would probably delay death, such as turning off a respirator, stopping medications or food and water and allowing the person to dehydrate or starve or not delivering (cardiopulmonary resuscitation), which permits natural death to occur.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Active euthanasia is a positive merciful act to end useless suffering or a meaningless existence. It is an act of commission, e.g. by giving large doses of drugs to hasten death. Option C: Non-voluntary refers to cases of persons incapable of making their wishes known, e.g., in persons with irreversible coma or severely defective infants. Euthanasia advocates the administration of lethal doses of opium or other narcotic drugs. It has no legal sanction. Option D: Voluntary euthanasia means at the person's will, and involuntary means against the person's will,e., compulsory.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A medical practitioner in a rural area was in his clinic. Some known person from the area came to him for a medical certificate. He was in his village for a wedding and wanted to submit the certificate to his employer for medical leave. Issuing false medical certificates by a doctor is punishable under?", "options": [{"label": "A", "text": "137 sec", "correct": false}, {"label": "B", "text": "127 sec", "correct": false}, {"label": "C", "text": "147 sec", "correct": false}, {"label": "D", "text": "197 sec", "correct": true}], "correct_answer": "D. 197 sec", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>197 sec Section 197 IPC - Issuing or signing false certificate Whoever issues or signs any certificate required by law to be given or signed, or relating to any fact of which such certificate is by law admissible in evidence, knowing or believing that such certificate is false in any material point, shall be punished in the same manner as if he gave false evidence.</p>\n<p><strong>Random:</strong></p><p>Explanation for Incorrect Options:- Option: A, B & D . These sections are unrelated to issuing false</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Euthanasia is:", "options": [{"label": "A", "text": "Recently recognised in India", "correct": true}, {"label": "B", "text": "Recognized worldwide.", "correct": false}, {"label": "C", "text": "Recognized in all states in the USA", "correct": false}, {"label": "D", "text": "Not followed in any country.", "correct": false}], "correct_answer": "A. Recently recognised in India", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Recently recognised in India It is not recognised worldwide It is not recognised in all the states of the USA. It is followed in some countries. Quick revision points: Euthanasia Types Active or positive – the act of commission Passive or negative –the act of omission Voluntary – with consent Involuntary – without consent Countries to legalise euthanasia Netherlands, Belgium, Luxembourg, Switzerland, Thailand Euthanasia in INDIA 7th March 2011 – Supreme Court allowed - passive – euthanasia</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The nut shown in the Illustration is used to produce", "options": [{"label": "A", "text": "Artificial incised wound", "correct": false}, {"label": "B", "text": "Lacerated wound", "correct": false}, {"label": "C", "text": "Artificial bruise", "correct": true}, {"label": "D", "text": "Artificial laceration", "correct": false}], "correct_answer": "C. Artificial bruise", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892586254-QTDF032001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Artificial bruise The given picture shows marking nut Artificial Bruises: Some irritant substances, when applied to the skin produce injuries, which simulate bruises Juice of marking nut, Calotropis plumbago rose. They are produced to make a false charge of assault.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B, & D. The image shown is the Marking nut. It doesn't produce an artificial incised wound lacerated wound or artificial laceration.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A man was involved in a scuffle and has some injuries on his body. The condition shown in the illustration occurs due to:", "options": [{"label": "A", "text": "Friction abrasion", "correct": false}, {"label": "B", "text": "Patterned abrasion", "correct": false}, {"label": "C", "text": "Imprint abrasion", "correct": false}, {"label": "D", "text": "Contusion", "correct": true}], "correct_answer": "D. Contusion", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892586395-QTDF032002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Contusion Hemorrhages in the soft tissues around the eyes and in the eyelids (spectacle hematoma ; black eye), may be caused by: Direct trauma as in contusion such as a punch in the eye, Blunt impact to the forehead, the blood gravitating downwards over the supraorbital bridge, Fracture of the floor of the anterior fossa of the skull. A bruise behind the ear may indicate a basal fracture, rather than a direct blow behind the ear.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Pressure Abrasions /crushing abrasion/friction abrasion They are caused by the crushing of the superficial layers of the epidermis and are associated with a bruise of the surrounding area. If the movement of the instrument is around 90° to the skin, a pressure type of abrasion occurs. In this type, the movement is slight and largely directed inwards. The ligature mark in cases of hanging and strangulation and the teeth bite marks are examples. Option B: Patterned abrasion Impact abrasions and pressure abrasions reproduce the pattern of the object causing it and are called patterned abrasions. Patterned injury is any injury that suggests an inflicting instrument or unique means of its causation. Patterned abrasions are produced when the force is applied at a right angle to the surface of the If the skin is struck with a weapon having a patterned surface, or the body falls against a patterned surface, the abrasion of the epidermis is caused by the ridges of the object, if it has a profile of varying height. The skin may be compressed into the cavities of the pattern with capillary damage leading to an intradermal bruise, e.g., when a motor tire passes over the skin. Other examples of patterned abrasion are imprints of bicycle chains, weaves of coarse fabrics, the spiral of electric wires, ropes, serrated knives, etc. Multi-thronged whip, such as a cat-o-nine-tails, leaves a series of linear abrasions or superficial tears. Usually, the pattern and shape are non-specific. Option C: Impact Abrasions (contact or imprint abrasions): They are caused by impact with a rough object when the force is applied at or near a right angle to the skin surface. The abrasion is slightly depressed below the surface unless there is bulging due to underlying contusion or local edema. If the impact is forcible, the dermis is damaged with an underlying bruise. When a person is knocked down by a motor car, the pattern of the radiator grille, a headlamp rim, or the tread of the tire may be seen on the skin, which may contain road dirt, paint flakes, grease, etc. Impact by a solid object may produce abrasion at the periphery where the skin is forced downwards. If a person strikes a flat and relatively smooth surface, an abrasion can be produced which shows little or no linear markings, as in traffic accidents.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Some bodies were recovered from a bus that was involved in a road mishap. Identify the type of injury as shown in the illustration:-", "options": [{"label": "A", "text": "Point scratch", "correct": false}, {"label": "B", "text": "Brush burn", "correct": true}, {"label": "C", "text": "Ectopic bruising", "correct": false}, {"label": "D", "text": "Incised wound", "correct": false}], "correct_answer": "B. Brush burn", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892586408-QTDF032003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Brush burn An abrasion caused by violent lateral (tangential) rubbing against a surface as in dragging over the ground is called brush burn or gravel rash. It is a scraping injury over a large area. \"Friction burn\" (scuff or brush abrasion) is an extensive, superficial, reddened excoriated area without serous ooze or bleeding and with little or no linear mark. It may occur due to tangential contact with a smooth surface or when the skin is covered by clothing.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Point Scratch: The shown image is covering an area not just a line or scratch. Hence is not the answer. Option: C. Ectopic bruising, or Percolated or Migratory contusion:- The bruise which appears in some other site apart from the area of impact. Option: D. An incised wound (cut, slice) is a clean cut through the tissues, (usually the skin and subcutaneous tissues, including blood vessels), caused by sharp-edged instruments. The wound is longer than it is deep.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person kills himself like shown in the given Image below. Choose the wrong statement", "options": [{"label": "A", "text": "It's called hara-kiri", "correct": false}, {"label": "B", "text": "The person inflicts with a short sword", "correct": false}, {"label": "C", "text": "There's an increase in intra-abdominal pressure", "correct": true}, {"label": "D", "text": "The cardiac return is decreased", "correct": false}], "correct_answer": "C. There's an increase in intra-abdominal pressure", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892586723-QTDF032004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>There's an increase in intra-abdominal pressure HARA-KIRI: The sudden evisceration of the internal organs causes a sudden decrease of intra-abdominal pressure and cardiac return, producing sudden cardiac collapse.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. It is an unusual type of suicide, in which the victim inflicts a single large wound on the abdomen with a short sword while in a sitting position or falls forward upon a ceremonial sword and pulls out the To produce impalement onto a knife, there should be enough momentum by the victim moving toward the knife and it would need to be fixed firmly in some way. The sudden evisceration of the internal organs causes a sudden decrease in intra-abdominal pressure and cardiac return, producing sudden cardiac collapse.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A child was rescued from a factory where he was working as a child laborer. He had multiple injuries, some were old and some were new. What is the age of the given bruise", "options": [{"label": "A", "text": "2 days", "correct": true}, {"label": "B", "text": "4 days", "correct": false}, {"label": "C", "text": "6 days", "correct": false}, {"label": "D", "text": "8 days", "correct": false}], "correct_answer": "A. 2 days", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892588448-QTDF032005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>2 days DETERMINATION OF THE AGE OF THE BRUISE At first: Red(oxyhemoglobin) Few hours to 3 days: Blue( deoxyhemoglobin)</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B . 4th day: Bluish-black to brown (hemosiderin). Option: C . 5 to 6 days: Greenish (biliverdin) Option: D . 7 to 12 days: Yellow (bilirubin). 2 weeks: Normal</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted with multiple injuries and a report of those injuries was made. Bruises are of less importance than abrasions because:", "options": [{"label": "A", "text": "Their size may not correspond to the size of the weapon", "correct": false}, {"label": "B", "text": "They may become visible several hours or even one to two days after the injury", "correct": false}, {"label": "C", "text": "Both of the above", "correct": true}, {"label": "D", "text": "Both bruise and abrasion are equally important", "correct": false}], "correct_answer": "C. Both of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both of the above Bruises are of less value than abrasions because: Option A : Their size may not correspond to the size of the weapon. Option B : They may become visible several hours or even one to two days after the injury. They may appear away from the actual site of injury. They do not indicate the direction in which the force was applied.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "“X”, “Y” and “ Z” are friends. X committed suicide due to personal issues. Y was the first person to see his dead friend. Since Y was not on good terms with Z off late, he applied the juice of a marking nut on X's dead body to mislead the case. Y also registered a case in the police station stating that Z has killed X and it’s not suicide. What will be the features produced due to the juice of marking nut", "options": [{"label": "A", "text": "Colour of the bruise is dark brown", "correct": true}, {"label": "B", "text": "Shape is usually round", "correct": false}, {"label": "C", "text": "Margins are not well defined", "correct": false}, {"label": "D", "text": "Colour of the bruise changes with time.", "correct": false}], "correct_answer": "A. Colour of the bruise is dark brown", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Colour of the bruise is dark brown DIFFERENTIATE BETWEEN ARTIFICIAL BRUISE & TRUE BRUISE Findings Artificial Bruise True Bruise Cause Juice of Plant Blunt force Situation On accessible parts Any part Color Dark brown Changes of color Margins Well defined Less defined Shape Irregular Shape of weapon Swelling, Redness, & ecchymosis Not present Present with slight swelling Contents Serum Blood Itching Present Absent Chemical Tests Positive Negative</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was taken to the accident wing after a road mishap. Identify the type of injury", "options": [{"label": "A", "text": "Stretch laceration", "correct": false}, {"label": "B", "text": "Split laceration", "correct": false}, {"label": "C", "text": "Cut laceration", "correct": false}, {"label": "D", "text": "Shearing laceration", "correct": true}], "correct_answer": "D. Shearing laceration", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892592479-QTDF032008IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Shearing laceration Avulsion (shearing laceration) : An avulsion is a laceration produced by sufficient force (shearing force) delivered at an acute angle to detach (tear off) a portion of a traumatized surface or viscus from its attachments. The shearing and grinding force by weight, such as a lorry wheel passing over a limb may produce separation of the skin from the underlying tissues (avulsion) over a relatively large area. This is called \"flying\"</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Stretch Lacerations : Overstretching of the skin, if it is fixed, will cause a There is localized pressure with a pull which increases until tearing occurs and produces a flap of skin, which is peeled off the underlying bone or deep fascia. This is seen in the running over by a motor vehicle, and the flap may indicate the direction of the vehicle. They can occur from kicking, and also when sudden deformity of a bone occurs after fracture, making it compound. Option: B. Split laceration Splitting occurs by crushing the skin between two hard objects. Scalp lacerations occur due to the tissues being crushed between the skull and some hard object, such as the ground or a blunt instrument Splits are not undermined but show tissue bridges. Option: C. Cut Lacerations : Cut lacerations may be produced by a heavy relatively sharp-edged instrument such as an axe, hatchet, or etc. The margins are usually abraded with bruising.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "One of the following produces toxic hypothermia:", "options": [{"label": "A", "text": "Salicylates", "correct": false}, {"label": "B", "text": "Anticholinergics", "correct": false}, {"label": "C", "text": "Antidepressants", "correct": false}, {"label": "D", "text": "Opioids", "correct": true}], "correct_answer": "D. Opioids", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Opioids Combined with environmental exposure, opioid overdose can cause profound hypothermia. Opioid abuse and other drug abuse impair thermoregulation, leading to severe hypothermia. Both drug overdose and severe hypothermia can cause cardiac arrest.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person drink cleaning fluid and now presented with stomach perforation and peritonitis. Perforation of the stomach is most common in", "options": [{"label": "A", "text": "Hydrochloric acid", "correct": false}, {"label": "B", "text": "Sulphuric acid", "correct": true}, {"label": "C", "text": "Nitric acid", "correct": false}, {"label": "D", "text": "Oxalic acid", "correct": false}], "correct_answer": "B. Sulphuric acid", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sulphuric acid Perforation of the stomach is more common with sulphuric acid. Perforation may occur with the escape of gastric contents into the peritoneal cavity, and if the patient lives for a few hours, chemical peritonitis and corrosion of organs is seen.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Discolouration of skin as shown in the image occur due to", "options": [{"label": "A", "text": "Nitrous oxide", "correct": false}, {"label": "B", "text": "Nitric acid", "correct": true}, {"label": "C", "text": "Sulphuric acid", "correct": false}, {"label": "D", "text": "Phosphoric acid", "correct": false}], "correct_answer": "B. Nitric acid", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893805756-QTDF068004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Nitric acid Nitric acid (aqua fortis; the red spirit of nitre) is a clear, colourless, fuming, heavy liquid, and has a peculiar and choking odour. In concentrated form, it combines with organic matter and produces a yellow discolouration of tissue due to the production of picric acid (xanthoproteic reaction)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The xanthoproteic reaction is seen in poisoning with:", "options": [{"label": "A", "text": "Hydrochloric acid", "correct": false}, {"label": "B", "text": "Nitric acid", "correct": true}, {"label": "C", "text": "Sulfuric acid", "correct": false}, {"label": "D", "text": "Both A. and B. above", "correct": false}], "correct_answer": "B. Nitric acid", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Nitric acid Nitric acid in its concentrated form combines with organic matter and produces an yellow discolouration of tissue due to the production of picric acid (xanthoproteic reaction).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A lady drank kerosene after a fight with her husband. Her family brought her to the emergency. In Kerosene poisoning, all are useful EXCEPT:", "options": [{"label": "A", "text": "Gastric lavage", "correct": true}, {"label": "B", "text": "Antacids", "correct": false}, {"label": "C", "text": "Bland diet", "correct": false}, {"label": "D", "text": "Intravenous fluids", "correct": false}], "correct_answer": "A. Gastric lavage", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Gastric lavage C/I is same for gastric lavage/stomach wash/ use of Boas’ tube/ Ewald’s tube- Absolute- corrosive poisons including acid, alkali and petroleum (KEROSENE). Relative- Convulsions (strychnine, tetanus), coma, volatile poisons, esophageal varices, diathesis, hypothermia.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B, C & D: These are used for the symptomatic management of corrosive poisons.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient was admitted after ingesting toilet cleaner after a fight with his wife. Ingestion of caustic causes mucosal damage due to:", "options": [{"label": "A", "text": "Its hygroscopic action", "correct": true}, {"label": "B", "text": "It has glue-like action", "correct": false}, {"label": "C", "text": "It's programmed to stick", "correct": false}, {"label": "D", "text": "It has a high affinity for mucosa", "correct": false}], "correct_answer": "A. Its hygroscopic action", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Its hygroscopic action Chief alkali poisons – Ammonia, KOH, NaOH, Ca (OH)2, Na / K CO3. Action:- Extraction of water from tissues. Coagulation of cellular proteins Conversion of Hb to Haematin When ingested, they cause liquefaction necrosis of GI mucosa, mainly affecting the squamous epithelium of esophagus and thus permitting deeper invasion of tissues with deep burns and marked edema. They cause more severe injury than acids because they dissolve proteins and saponify fat. They produce soft, edematous, translucent gelatinous friable eschars and thus stricture formation is much more common with alkalies than acids. Treatment:- Demulscents, Oxygen inhalation, steroids to reduce stricture formation and symptomatic. PM findings: Angles of mouth, lips and oral cavity are dark and parchment-like. Esophagus and stomach show corrosion and the formation of slimy eschars. Esophageal stricture is the most common finding if the patient survives for a certain time. Perforation of esophagus and stomach is very rare.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C & D These are not the mechanism of action.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Preservation of viscera till their analysis is important. Which of the following is never used in Toxicological analysis:", "options": [{"label": "A", "text": "Saturated NaCl solution", "correct": false}, {"label": "B", "text": "Formalin", "correct": true}, {"label": "C", "text": "Rectified spirit", "correct": false}, {"label": "D", "text": "Sodium fluoride", "correct": false}], "correct_answer": "B. Formalin", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Formalin Formalin is not used as a preservative for chemical analysis because extraction of poison becomes difficult. Preservation of viscera: Anyone of the following two preservatives may be used: A saturated solution of common salt (NaCl, i.e. sodium chloride): Most commonly used preservative (easily available & cheap) It is indicated in all poisoning cases except Corrosives Rectified spirit Best preservative Indicated for most of the poisons except alcohol, acetic acid, Chloral hydrate, Chloroform, formaldehyde, formic acid, kerosene, phosphorus, paraldehyde, Phenol Blood: For every 10 ml, use 30 mg potassium oxalate (anticoagulant) and 100 mg sodium fluoride (prevents glycolysis) Urine: For every 10 ml use 100 mg of sodium fluoride Vitreous humor: For every 10 ml use 100 mg of sodium fluoride</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Formalin is used as a preservative only for histopathology. To preserve the specimen, the concentration of formalin used is:", "options": [{"label": "A", "text": "1%", "correct": false}, {"label": "B", "text": "5%", "correct": false}, {"label": "C", "text": "10%", "correct": true}, {"label": "D", "text": "40%", "correct": false}], "correct_answer": "C. 10%", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>10% Specimens for pathological examination and museum specimens are preserved in 10% Formalin. Formalin is ordinarily available as a 40% solution from the market, it is diluted to 10% for use in the preservation of specimens. Formalin is never used to preserve toxicological specimens as it would denature the poisons and make the estimation of poisons difficult.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Sometimes, one injury to the head can cause injury to the brain at multiple places. Incorrect statement with respect to the Image given below is amongst which of the following?", "options": [{"label": "A", "text": "Coup (blow; impact) means that the injury is located beneath the area of impact, and results directly from the impacting force", "correct": false}, {"label": "B", "text": "Contrecoup means that the lesion is present in an area opposite the side of the impact", "correct": false}, {"label": "C", "text": "Contrecoup injuries can also occur when a blow is struck on a fixed head", "correct": false}, {"label": "D", "text": "A line drawn between the centres of the coup and contrecoup indicates the direction of impact relative to the surface", "correct": true}], "correct_answer": "D. A line drawn between the centres of the coup and contrecoup indicates the direction of impact relative to the surface", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1683825122948-QTDF043001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A line drawn between the centres of the coup and contrecoup indicates the direction of impact relative to the surface A line drawn between the centres of the coup and contrecoup indicates the direction of impact relative to the head.</p>\n<p><strong>Random:</strong></p><p>Explanation for Incorrect Options: - CONTRECOUP LESIONS: Option: A. Coup (blow; impact) means that the injury is located beneath the area of impact, and results directly from the impacting force. Option: B. Contrecoup means that the lesion is present in an area opposite the side of the impact of the body to slide relatively to each other in a direction parallel to their planes of contact\". Fracture of the skull may not occur, even in the presence of severe coup and contrecoup injuries. Option: C. Contrecoup injuries can also occur when a blow is struck on a fixed head. If a person is lying on the ground or against some other unyielding surface, a heavy blow on the upper temporal or parietal area may cause typical contrecoup injuries either in the contralateral temporal or parietal cortex or against the falx on the inner side of the ipsilateral lobe. There is often coup injury also. Mechanism: Contrecoup injury is caused when the moving head is suddenly decelerated by hitting a firm surface, e.g., striking the head on the ground during a fall, usually seen in traffic accidents. Subdural or subarachnoid haemorrhage may be caused as a contrecoup lesion. The sudden arrest of the head results in the brain which is still in motion, striking the arrested skull A blow to the head causes the skull to move forward, but the brain lags behind for a brief period and the skull strikes the brain (acceleration injury). Medicolegal Importance: A blow to the head produces coup contusions, while contrecoup contusions are either small or absent. A fall on the head produces contrecoup contusions while coup contusions are mall or absent. Contrecoup injuries are rare before the age of three years. Contrecoup injury is seen in the skull, brain, liver, heart, and lungs.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A slow-moving car swerved into an intersection and over the curb onto the sidewalk. The right front door flew open, the driver was found sprawled across the seat in a pool of vomitus. The odor of alcohol was present and the driver was observed to be ataxic and incontinent, mumbling an incoherent story. A cursory examination resulted in a diagnosis of 'drunk'. What should be done next", "options": [{"label": "A", "text": "Should be sent to jail", "correct": false}, {"label": "B", "text": "Should be kept in police custody till the court gives the verdict", "correct": false}, {"label": "C", "text": "Should be kept in police custody for the next 24 hours to observe his behavior and gestures", "correct": false}, {"label": "D", "text": "Should be shifted to the hospital", "correct": true}], "correct_answer": "D. Should be shifted to the hospital", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Should be shifted to the hospital Head injury and acute alcoholic intoxication: A person may be confused and disorientated after a head injury which may simulate acute alcoholic intoxication. If an intoxicated person sustains a head injury, it may not be possible to assess to what degree his condition is due to head injury or alcoholic intoxication. Such a person should not be kept in police custody but should be admitted to a hospital for observation.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B, & C. Since he is intoxicated, it may not be possible to assess his head injury and its effects. Hence such a person should not be kept in police custody or jail but admitted to a hospital for observation and necessary treatment.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person with a head injury was admitted to the emergency. After 3 days, a repeat CT head was done. The following Image gives clue about this. Which of the following?", "options": [{"label": "A", "text": "Duret hemorrhage", "correct": true}, {"label": "B", "text": "Consequence of coup injury", "correct": false}, {"label": "C", "text": "Consequence of countercoup injury", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "A. Duret hemorrhage", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1683825123458-QTDF043003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Duret hemorrhage DURET HAEMORRHAGES are secondary herniation hemorrhages of the midbrain and pons, ranging from small streaks to massive confluent hemorrhage in the midline. They commonly occur with asymmetrical herniation of the brain stem. Uncal grooving indentation of the cerebellar tonsils are common postmortem findings and must not be misinterpreted as evidence of uncinate herniation and cerebellar com</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B & C. Coup and Countercoup Injuries and its impacts are not significant according to this CT scan. Hence these options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Ravi kicks Ram on his chest directly in the region of his heart. Ram succumbs due to abnormal heart rhythm. What is the term given to this?", "options": [{"label": "A", "text": "Commotio Cordis", "correct": true}, {"label": "B", "text": "Contrecoup injuries", "correct": false}, {"label": "C", "text": "Both A and B", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "A. Commotio Cordis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Commotio Cordis CARDIAC CONCUSSION:- A cardiac concussion can occur after a sudden forceful impact directed at the mid-anterior chest wall in the region of the heart, i.e. COMMOTIO CORDIS. Death occurs due to ventricular fibrillation or asystole. The functional disturbance may be caused by reflex coronary vasoconstriction and myocardial ischemia or by abnormal autonomic responses.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. CONTRECOUP CONTUSIONS of the heart are seen over the posterior wall of the left ventricle. They are seen in traffic accidents in which the driver is thrown forward against the steering wheel and the heart is compressed against the vertebrae. Option: C & D. Since Option A is correct and B is wrong. C and D are not significant for this question.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was brought with multiple fresh injuries over the body with suspicion of physical assault. Police asked for an opinion on whether the injuries are grievous. All are grievous hurts EXCEPT:", "options": [{"label": "A", "text": "Dislocated shoulder", "correct": false}, {"label": "B", "text": "Incised wound on the abdominal wall without peritoneal injury", "correct": true}, {"label": "C", "text": "Nasal bone fracture", "correct": false}, {"label": "D", "text": "Permanent disfigurement of the face", "correct": false}], "correct_answer": "B. Incised wound on the abdominal wall without peritoneal injury", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Incised wound on the abdominal wall without peritoneal injury Incised wound on the abdominal wall without peritoneal injury’ is a simple injury. If the peritoneum had been breached, it would have been a grievous injury or maybe a dangerous injury. All other injuries- dislocation, fracture, and disfiguration are grievous injuries as per Section 320 IPC.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, C & D The following kinds of hurt only are designated as “grievous”: The following kinds of hurt only are designated as “grievous”: Emasculation Permanent privation of the sight of either eye. Permanent privation of the hearing of either ear. Privation of any member or joint. Option: A . Destruction or permanent impairing of the powers of any member or joint. Option D Permanent disfiguration of the head or face. Option: C Fracture or dislocation of a bone or tooth. Any hurt which endangers life or which causes the sufferer to be during the space of twenty days in severe bodily pain, or unable to follow his ordinary pursuits.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "First-class judicial Magistrate sentenced punishment of one year to the accused. The punishment can be enhanced by all of the following magistrates expect", "options": [{"label": "A", "text": "High court judge", "correct": false}, {"label": "B", "text": "Second class judicial magistrate", "correct": true}, {"label": "C", "text": "Supreme court judge", "correct": false}, {"label": "D", "text": "Chief judicial magistrate", "correct": false}], "correct_answer": "B. Second class judicial magistrate", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Second class judicial magistrate Second-class judicial magistrate holds lesser power than other judges in the given options. Any sentence awarded by a Court may be enhanced or decreased by a higher Court. Government has the power to suspend, repeal or commute any sentence passed by a Court of law (S.432 and 433 Cr. P .C. ). Hence High Court judge, Supreme Court Judge and the Chief Judicial Magistrate can enhance the punishment. (Options A, C and D).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A child was brought to you for a medical examination as he was involved in a theft. The police asked you to prioritise the case as they have to present the child in a juvenile court. Juvenile court is usually presided by:", "options": [{"label": "A", "text": "Session judge", "correct": false}, {"label": "B", "text": "Additional session judge", "correct": false}, {"label": "C", "text": "Chief judicial magistrate", "correct": false}, {"label": "D", "text": "1st class woman magistrate", "correct": true}], "correct_answer": "D. 1st class woman magistrate", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1st class woman magistrate According to the Justice Juvenile Act, children are human beings below the age of 18 years. Juvenile courts try offences committed by juveniles (below the age of 18 years). Juvenile court is usually presided over by a first-class woman magistrate.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect options:- Options: A, B, & C : Since a first-class woman magistrate presides over the juvenile court, Sessions judge, additional session judge and chief judicial magistrate are the wrong options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "If a witness receives the summons from all of the following courts to attend summons on the same day, which court he should attend first?", "options": [{"label": "A", "text": "Fast track court", "correct": true}, {"label": "B", "text": "Chief metropolitan magistrate.", "correct": false}, {"label": "C", "text": "Chief judicial magistrate.", "correct": false}, {"label": "D", "text": "Assistant Sessions court", "correct": false}], "correct_answer": "A. Fast track court", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Fast track court Criminal Courts have priority over civil Courts. If a witness is summoned by two Courts on the same day, one of which is criminal and the other civil, he should attend the Criminal Court and inform the Civil Court of his inability to attend, giving his reasons. Higher Courts have priority over the lower. If he is summoned from two Courts of the same status, he must attend the Court from where he received the summons first, informing the other Court about it. He can attend the second Court after finishing his evidence in the first Court.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C, & D: Since the witness has to attend the higher Court, other Options are not the correct answers</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A drunkard was walking home after a party. On the way, he stumbled upon a beggar who was sleeping on the sidewalk. This led to a fight and eventually to the murder of the beggar by the drunkard. A case was filed and the drunkard was accused for the death of the beggar. A public prosecutor was recruited for representing the :", "options": [{"label": "A", "text": "State", "correct": true}, {"label": "B", "text": "Drunkard", "correct": false}, {"label": "C", "text": "The person who hosted the party", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "A. State", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>State In criminal cases (murder, sexual assault, assault ) etc., the State will represent the interest of the public (here the beggar) by appointing a Public prosecutor. The accused ( here the drunkard) will be the defendant.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C, & D. Since the public prosecutor represents the state (the beggar), other Options are not correct.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person accused of a rape case was handed over to police custody by the court for further interrogation. Next day morning the accused was found dead inside the police cell. An inquest, in this case, will be done by-", "options": [{"label": "A", "text": "Coroner", "correct": false}, {"label": "B", "text": "Police", "correct": false}, {"label": "C", "text": "Judicial magistrate", "correct": true}, {"label": "D", "text": "Medical examiner", "correct": false}], "correct_answer": "C. Judicial magistrate", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Judicial magistrate An inquest is an enquiry or investigation into the cause of death. Two types of the inquest are held in India Magistrate inquest -this is conducted by the district magistrate, subdivisional magistrate tahsildar or other executive magistrate empowered by the state government. The judicial magistrate's inquest is done in case of death in police custody, death in police firing, death in prison, reformatories, and borstal school. Inquest by the executive magistrate is done in death in a mental asylum, dowry death, and</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Coroners’ inquest is a type of inquest done in the UK and some other countries but not in India. The coroner conducts inquest in all unnatural and suspicious death. The doctor is summoned to his court to give evidence at the inquest. Coroner’s court is a court of enquiry. He has judicial powers. Option: B. In a Police inquest, the officer in charge of the police station conducts the inquest, he is the investigating officer. When the officer in charge of the police station receives information that a person has committed suicide or killed by someone or died under the circumstances raising a reasonable suspicion, he immediately gives intimation about it to the nearest executive magistrate empowered to hold an inquest and proceed to the place where the body of such a deceased person is. Option: D. Medical examiner’s system is practised in the USA, Canada, and Japan but not in India. The inquest is conducted by a medical person but he does not have any judicial power. It is the best type of interest overall.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A businessman, following a stab injury to the chest, was in critical condition. His dying declaration was taken. All the following statements are true except:", "options": [{"label": "A", "text": "If the victim survives after recording the dying declaration, it has corroborative value", "correct": false}, {"label": "B", "text": "Oath is administered before recording the dying declaration", "correct": true}, {"label": "C", "text": "Signature or thumb impression of the declarant must be taken", "correct": false}, {"label": "D", "text": "Doctor should take the declaration in the presence of two witnesses", "correct": false}], "correct_answer": "B. Oath is administered before recording the dying declaration", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Oath is administered before recording the dying declaration Oath is not taken before the dying declaration because of the belief that the dying person tells the truth.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. In a dying declaration, if the declarant survives, the declaration is not admitted but has a corroborative value and the person is called to give oral evidence. Option: C. Signature or thumb impression of the declarant must be taken. Option: D. If there is no time to call the magistrate then the doctor should take the declaration in the presence of two witnesses.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A murder convict was given a death sentence. Who can commute a death sentence?", "options": [{"label": "A", "text": "High court.", "correct": false}, {"label": "B", "text": "Supreme Court.", "correct": false}, {"label": "C", "text": "President of India.", "correct": false}, {"label": "D", "text": "Any of the above.", "correct": true}], "correct_answer": "D. Any of the above.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Any of the above. Categories of criminal Courts: Supreme Court, High Court, Sessions Court, Magistrate Court Supreme Court & High Court Judges: Can give any punishment Can increase or decrease punishments given by lower courts. The President of India has the power to grant pardons, remissions of punishments and COMMUTATION of DEATH SENTENCE</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Non-compliance with a court summons from a criminal court may be punished under section:", "options": [{"label": "A", "text": "S 174 IPC", "correct": true}, {"label": "B", "text": "S 197 IPC", "correct": false}, {"label": "C", "text": "S 201 IPC", "correct": false}, {"label": "D", "text": "S 351 IPC", "correct": false}], "correct_answer": "A. S 174 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>S 174 IPC Nonattendance in obedience to an order from Court of law intentionally i.e. summons renders imprisonment up to six months or a fine up to one thousand rupees, or both</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. 197, I.P.C.: Issuing or signing false certificates (imprisonment up to seven years). Option: C .201, I.P.C.: Causing disappearance of evidence of the offence, or giving false information to screen offenders (imprisonment up to ten years) Option: D. 351, I.P.C: An assault is an offer or threat or attempt to apply force to the body of another in a hostile manner. It may be a common assault or with an intent to murder</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Sexual assault scenarios can leave a victim in a persistent vegetative state. A vegetative state is a due to injury to:", "options": [{"label": "A", "text": "Brain stem", "correct": false}, {"label": "B", "text": "Cerebral cortex", "correct": true}, {"label": "C", "text": "Cerebral cortex along with brain stem", "correct": false}, {"label": "D", "text": "Spinal cord", "correct": false}], "correct_answer": "B. Cerebral cortex", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cerebral cortex CORTICAL OR CEREBRAL DEATH with an intact brain stem produces a vegetative state in which respiration continues, but there is a total loss of power of perception by the senses. This state of deep coma can be produced by cerebral hypoxia, toxic conditions or widespread brain injury</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A, C & D . Injury to the brainstem or spinal cord does not leave a victim in a persistent vegetative state. Hence these Options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The Kevorkian sign is fragmentation or segmentation of the blood columns in the:", "options": [{"label": "A", "text": "Cerebral vessels", "correct": false}, {"label": "B", "text": "Retinal vessels", "correct": true}, {"label": "C", "text": "Pulmonary veins", "correct": false}, {"label": "D", "text": "Renal arteries", "correct": false}], "correct_answer": "B. Retinal vessels", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Retinal vessels Fragmentation or segmentation (tuking or shunting) of the blood columns (Kevorkian sign) in the retinal vessels appear within minutes after death and persists for about an hour. This occurs all over the body due to loss of blood pressure but it can be seen only in the retina by ophthalmoscope. The retina is pale for the first two hours. At about six hours, the disk outline is hazy and becomes blurred in 7 to 10 hours.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A, C & D . Since the Kevorkian sign is fragmentation or segmentation of only retinal blood vessels, other Options are not relevant to this question. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Under the Indian evidence act, a person is presumed to be dead, if a proof is produced that the same person has not been heard by his friends and relatives for:", "options": [{"label": "A", "text": "7 Years", "correct": true}, {"label": "B", "text": "12 Years", "correct": false}, {"label": "C", "text": "20 Years", "correct": false}, {"label": "D", "text": "30 Years", "correct": false}], "correct_answer": "A. 7 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>7 Years If proof is produced that the same person has not been heard from for seven years by his friends and relatives, death is presumed (S. 108, I.E.A.).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : B, C & D . Since 7 years is the time limit to presume the death of a person, Other timeframes in the options are not relevant to this question. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person sat on a hunger strike to force the government to accept his demands. After 5 days, a government doctor came to examine his condition. How many days a person can live without food and water?", "options": [{"label": "A", "text": "1 to 2 days", "correct": false}, {"label": "B", "text": "2 to 4 days", "correct": false}, {"label": "C", "text": "5 to 7 days", "correct": false}, {"label": "D", "text": "10 to 12 days", "correct": true}], "correct_answer": "D. 10 to 12 days", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>10 to 12 days If both water and food are completely withdrawn, death occurs in 10 to 12 days. If food alone is withdrawn death occurs in 6 to 8 weeks or even more. Death usually occurs when about 70 to 90% of body fat, and 20% of body protein are lost. Newborns may survive for 7 to 10 days without food or water.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A, B & C . Since 10 to 12 days are the time limit, a person can live without food and water, Other timeframes in the options are not relevant to this question. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A case of road traffic accident was brought for autopsy. The attending doctor decided to carry out a pyrogallol test. Pyrogallol test is used to detect:", "options": [{"label": "A", "text": "Fat embolism", "correct": false}, {"label": "B", "text": "Amniotic fluid embolism", "correct": false}, {"label": "C", "text": "Bone marrow embolism", "correct": false}, {"label": "D", "text": "Air embolism", "correct": true}], "correct_answer": "D. Air embolism", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Air embolism Pyrogallol test:- Used to detect air embolism. 4 ml. of a 2% freshly prepared pyrogallol solution is collected into two 10 ml syringes. To the first syringe, four drops of 0.5 M sodium hydroxide solution are Gas is aspirated from the right side of the heart. The needle is removed and replaced with a stopper, and the syringe is shaken. If air (oxygen) is present, the mixture turns brown. In the second syringe, some air is introduced and the test is repeated as a control. The solution should turn brown. This test helps to differentiate gas present in the heart from gas formed due to decomposition.</p>\n<p><strong>Random:</strong></p><p>Explanation For incorrect Options:- Option: A, B & C. Fat, amniotic fluid and bone marrow embolism are not related to pyrogallol test. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "There are many scenarios where false changes are introduced into the body after death which are called artefacts. In a dead body, the following cannot be simulated artificially after death:", "options": [{"label": "A", "text": "Rigor mortis", "correct": false}, {"label": "B", "text": "Cataleptic rigidity", "correct": true}, {"label": "C", "text": "Heat stiffening", "correct": false}, {"label": "D", "text": "Cold stiffening", "correct": false}], "correct_answer": "B. Cataleptic rigidity", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cataleptic rigidity No other condition simulates cadaveric spasm (cataleptic rigidity) and it cannot be produced by any method after death. Medicolegal importance of cadaveric spasm: - Occasionally, in case of suicide. The weapon, e.g., pistol or knife is seen firmly grasped in the victim's hand which is strong presumptive evidence of suicide. Attempts may be made to simulate this condition in\" order to conceal the But, ordinary rigor does not produce the same firm grip of a weapon, and the weapon may be placed in the hand in a way which could not have been used by a suicide. If the deceased dies due to assault, some part of clothing, e.g., button of his assailant or some hair may be firmly grasped in the hands. In case of drowning, material such as grass, weeds or leaves may be found firmly grasped in the hands, which indicates that the victim was alive on entering the water.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A, C & D . Rigor mortis, heat stiffening and cold stiffening can be simulated artificially even after death. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Corpus Delicti is?", "options": [{"label": "A", "text": "Unlawful imprisonment", "correct": false}, {"label": "B", "text": "The body of the offence", "correct": true}, {"label": "C", "text": "Criminal negligence", "correct": false}, {"label": "D", "text": "Exhumation", "correct": false}], "correct_answer": "B. The body of the offence", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The body of the offence THE CORPUS DELICTI: The corpus delicti (delicti=fault; offence)(the body of offence; the essence of crime) means, the facts of any criminal offence, e.g., murder. The corpus delicti of murder is the fact that a person died from unlawful violence. It includes the body of the victim and other facts which are conclusive of death by foul play, such as a bullet or a broken knife-blade found in the body and responsible for the Clothing showing marks of the weapon, and drawings and photographs of the deceased showing fatal injuries are also included in this term. The main part of corpus delicti is the establishment of the identity of the dead body, and infliction of violence in a particular way, at a particular time and place, by the person or persons charged with the crime and none other. The case against the accused cannot be established unless there is convincing proof of these points.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Since Corpus Delicti is related to the body of the offence, other Options like unlawful imprisonment, criminal negligence and exhumation are not related to it. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A woman jumps from the bridge into the river and succumbs. She must have died due to cessation of respiration. Cessation of respiration is a sign of", "options": [{"label": "A", "text": "Somatic death", "correct": true}, {"label": "B", "text": "Cellular death", "correct": false}, {"label": "C", "text": "Sign of decomposition and decay", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "A. Somatic death", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Somatic death Immediate (somatic death) Insensibility and loss of voluntary power. Cessation of respiration. Cessation of circulation.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Early (cellular death) Pallor and loss of elasticity of the skin Changes in the eye. Primary flaccidity of muscles. Cooling of the body. Postmortem lividity. Rigor mortis. Option : C. Late (decomposition and decay) Putrefaction Adipocere formation. Mummification Cessation of Respiration: This must be complete and continuous. The stethoscope is placed over the upper portions of the lungs and larynx where the faintest breath-sounds can be heard. Complete stoppage of respiration for more than 5 minutes usually causes death. Respiration may stop for a very short period without causing death. It may occur. As a purely voluntary act, Cheyne-Stokes breathing, Drowning, and Newborn infants. The feather test, mirror test and Winslow's test are of historical importance only.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Raman proves that his sibling Ravi is unheard of for almost 10 years So, Ravi is considered to be dead. Which of the following section deal with this", "options": [{"label": "A", "text": "Sec. 108 IEA", "correct": true}, {"label": "B", "text": "Sec. 107 IEA", "correct": false}, {"label": "C", "text": "Sec. 108 IPC", "correct": false}, {"label": "D", "text": "Sec. 107 IPC", "correct": false}], "correct_answer": "A. Sec. 108 IEA", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec. 108 IEA Burden of proving that person is alive who has not been heard of for seven years.—Provided that when the question is whether a man is alive or dead, and it is proved that he has not been heard of for seven years by those who would naturally have heard of him if he had been alive, the burden of proving that he is alive is shifted to the person who affirms it.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Sec 107 IEA The burden of proving the death of a person known to have been alive within thirty years.—When the question is whether a man is alive or dead, and it is shown that he was alive within thirty years, the burden of proving that he is dead is on the person who affirms it. Option: C. Sec 108 IPC A person abets an offence, who abets either the commission of an offence or the commission of an act which would be an offence if committed by a person capable by law of commit¬ting an offence with the same intention or knowledge as that of the abettor. Option: D. Sec 107 IPC Abetment of a thing.—A person abets the doing of a thing, who— (First) — Instigates any person to do that thing; or (Secondly) —Engages with one or more other person or persons in any conspiracy for the doing of that thing, if an act or illegal omission takes place in pursuance of that conspiracy, and to the doing of that thing; or (Thirdly) — Intentionally aids, by any act or illegal omission, the doing of that thing</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The following definition comes under which section of IPC \" Death denotes the death of a human being unless the contrary appears from the context \"", "options": [{"label": "A", "text": "Sec 46 IPC", "correct": true}, {"label": "B", "text": "Sec 44 IPC", "correct": false}, {"label": "C", "text": "Sec 45 IPC", "correct": false}, {"label": "D", "text": "Sec 47 IPC", "correct": false}], "correct_answer": "A. Sec 46 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec 46 IPC Section 46 IPC \"death\" denotes the death of a human being unless the contrary appears from the context.</p>\n<p><strong>Random:</strong></p><p>Explanation For the Incorrect Options:- Option: B. Section 44 “Injury”.—The word “injury” denotes any harm illegally caused to any person, in body, mind, reputation or proper¬typroperty. Option: Section 45 in The Indian Penal Code “Life”.—The word “life” denotes the life of a human being, unless the contrary appears from the context. Option: D. Section 47 in The Indian Penal Code “Animal”.—The word “animal” denotes any living creature, other than a human being</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Different organs of the body putrefy at different rates. The correct sequence of putrefaction:", "options": [{"label": "A", "text": "Heart-brain-uterus-spleen", "correct": false}, {"label": "B", "text": "Spleen-brain-heart-uterus", "correct": true}, {"label": "C", "text": "Heart-spleen-brain-uterus", "correct": false}, {"label": "D", "text": "Heart-brain-spleen-uterus", "correct": false}], "correct_answer": "B. Spleen-brain-heart-uterus", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Spleen-brain-heart-uterus The various organs are putrefied at different rates, depending on their structure, vascularity and access to air and bacteria. Generally, the organs show putrefactive changes in the following order. Larynx and trachea. Stomach, intestines, pancreas and spleen. Liver, lungs. Brain Heart Kidneys, bladder. Prostate, uterus. Skin, muscle, tendon. Bones</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The last organ to putrefy in man is:", "options": [{"label": "A", "text": "Brain", "correct": false}, {"label": "B", "text": "Lungs", "correct": false}, {"label": "C", "text": "Prostate", "correct": true}, {"label": "D", "text": "Seminal vesicle", "correct": false}], "correct_answer": "C. Prostate", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Prostate Generally, the organs show putrefactive changes in the following order. Larynx and trachea. Stomach, intestines, pancreas and spleen. (Option B) Liver, lungs. (Option A) Brain. Heart Kidneys, bladder. (Option C) Prostate, uterus. Skin, muscle, tendon. Bones</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Maggots in the summer season are seen within:", "options": [{"label": "A", "text": "12 hours", "correct": false}, {"label": "B", "text": "1-2 days", "correct": true}, {"label": "C", "text": "3-4 days", "correct": false}, {"label": "D", "text": "1 week", "correct": false}], "correct_answer": "B. 1-2 days", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1-2 days When skin decomposition begins, the eggs can be deposited between 8 to 24 hours in summer. The complete life cycle from egg to adult may take 5 to 6 days in summer and 8 to 20 days in winter.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D . Since the maggots are seen within one or two days, other time frames in these options are not relevant. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The first sign of decomposition in the Dead body, as shown in the Image, is", "options": [{"label": "A", "text": "Decomposition of liver & intestine", "correct": false}, {"label": "B", "text": "Greenish discoloration over Right iliac fossa", "correct": true}, {"label": "C", "text": "Greenish discolouration of dependent parts", "correct": false}, {"label": "D", "text": "Blood-stained froth from the mouth", "correct": false}], "correct_answer": "B. Greenish discoloration over Right iliac fossa", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893232262-QTDF054007IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Greenish discoloration over Right iliac fossa The first external sign of putrefaction in a body lying in the air is usually a greenish discolouration of the skin over the region of the caecum, which lies fairly superficially, and where the contents of the bowel are more fluid and full of bacteria.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, C & D: Since the first sign is the greenish discolouration in the right iliac fossa, other Options of liver and intestine, green colour in dependent parts and blood-stained discharge from the mouth are irrelevant in this context. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A dead body brought from the ward did not show any fall in the temperature after 2 hours. Postmortem caloricity may be seen in death due to the following:", "options": [{"label": "A", "text": "Massive haemorrhage", "correct": false}, {"label": "B", "text": "Cyanide poisoning", "correct": false}, {"label": "C", "text": "Corrosive poisoning", "correct": false}, {"label": "D", "text": "Septicemia", "correct": true}], "correct_answer": "D. Septicemia", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Septicemia Postmortem Caloricity: In this condition, the body's temperature remains raised for the first two hours after death. This occurs: When the regulation of heat production has been severely disturbed before death, as in sunstroke and in some nervous disorders, When there has been a significant increase in heat production in the muscles due to convulsions, as in tetanus and strychnine poisoning, etc., and When there has been excessive bacterial activity, as in septicaemic conditions. cholera and other fevers</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C . Massive haemorrhage, cyanide poisoning, and corrosive poisoning does not cause postmortem caloricity. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The following features were seen in a dead body, changes in the colour of the tissues the evolution of gases in the tissues the liquefaction of tissues. The same changes on the body's surface occur simultaneously in internal organs. These changes suggest the body has undergone what process or stage after death?", "options": [{"label": "A", "text": "Livor mortis", "correct": false}, {"label": "B", "text": "Primary Flaccidity", "correct": false}, {"label": "C", "text": "Putrefaction", "correct": true}, {"label": "D", "text": "Algor mortis", "correct": false}], "correct_answer": "C. Putrefaction", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Putrefaction The last stage of decomposition is the destruction of tissues/bodies. The disintegration of body tissues after death is known as decomposition. The terms decomposition and putrefaction are used as synonyms. Putrefaction usually follows the disappearance of rigor mortis. During the hot season, it may commence before rigor mortis has wholly disappeared from the lower extremities. Organisms/bacteria gain entry into tissues mainly from the alimentary tract and also through the respiratory tract, and they multiply in tissues. As they multiply, the bacteria spread via vessels using proteins and carbohydrates of blood as culture media. They release bacterial enzymes.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. Livor mortis - This is the bluish-purple or purplish-red (due to deoxyhaemoglobin) discolouration which appears under the skin in the most superficial layers of the dermis (rete mucosum) of the dependent parts of the body after death, due to capillo-venous distention. O ption B. Primary Flaccidity - During this stage, death is only somatic (no cellular death) and lasts one to two hours. All the muscles of the body begin to relax soon after death. The lower jaw falls, eyelids lose tension, and joints are flexible. The body flattens over areas in contact with the surface on which it rests (contact flattening). Option D. Algor mortis -It’s the process of cooling down a dead Heat is generated by the residual metabolic process (glycogenolysis) of dying tissues and by the metabolic activity of intestinal bacteria, due to which body temperature does not fall for some time. With the start of cooling, a temperature gradient develops from the surface to the core of any body part. The heat exchange between the core and the body's surface occurs only by conduction. At fi1·st, heat is lost from superficial layers of the body only. Due to the low velocity of heat transport inside the body, it takes some time for heat to be conducted from the deeper to the more superficial layers. Finally, the temperature gradient reaches the core. Internal organs cool primarily by conduction. Conductive heat exchange occurs due to the temperature difference between the body and its surroundings. The body heat is lost mainly by conduction and convection. In non-contact areas, heat exchange occurs by a conventional mechanism, which exceeds the contact surface.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The following image shows the Thigh of a cadaver. what type of post-mortem change is seen here", "options": [{"label": "A", "text": "Putrefaction", "correct": false}, {"label": "B", "text": "Marbling", "correct": true}, {"label": "C", "text": "Secondary Relaxation", "correct": false}, {"label": "D", "text": "Postmortem luminescence", "correct": false}], "correct_answer": "B. Marbling", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893232703-QTDF054011IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Marbling The superficial veins, especially over the roots of the limb, thighs, sides of the abdomen, shoulders, chest and neck, are stained greenish-brown or purplish-red depending on the total amount of sulphhaemoglobin formation within the affected vessels (linear branching pattern) due to the haemolysis of red cells, which stains the wall of the vessel and infiltrates into the tissue, giving a marbled appearance (red, then the greenish pattern in skin resembling the branches of a tree).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. Putrefaction- The disintegration of body tissues after death is known as decomposition. The terms decomposition and putrefaction are used as synonyms. Putrefaction usually follows the disappearance of rigor mortis. During the hot season, it may commence before rigor mortis has completely disappeared from the lower extremities. Option C. Secondary Relaxation- Flaccidity following rigor mortis is caused by the action of the alkaline liquids produced by putrefaction. Another view is that rigidity disappears due to the solution of myosin by an excess of acid produced during rigor mortis. A third view is that enzymes are developed in the dead muscle, which dissolves myosin by the process of autodigestion. Option D. Postmortem luminescence- Postmortem luminescence is usually due to contamination by bacteria, e.g., Photobacterium fischeri, and the light comes from them and not from putrefying material. Luminescent fungi, Armillaria mellea, is another source of light.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "What effect after putrefaction does the following image show?", "options": [{"label": "A", "text": "Skeletonisation", "correct": false}, {"label": "B", "text": "Adipocere", "correct": false}, {"label": "C", "text": "Blisters", "correct": true}, {"label": "D", "text": "Marbling of Skin", "correct": false}], "correct_answer": "C. Blisters", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893235006-QTDF054013IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Blisters Development of Foul-smelling Gases: The chemical processes in this stage are those of reduction, the complex proteins and carbohydrates being split into simpler compounds of arninoacids, ammonia, CO, C02, hydrogen sulphide, phosphorated hydrogen, methane and mercaptans. The gas formation in the blood vessels may force bloodstained fluid, air or liquid fat between the epidermis and dermis, forming small blisters in 18 to 24 hours. Blisters are formed first on the lower surfaces of the trunk and thighs, where tissues contain more fluid due to hypostatic oedema.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Skeletonisation- The time required for skeletonisation varies considerably and mainly depends on the ambient temperature, insect colonisation of the body and scavenger activity. A corpse can be skeletonised in a hot, humid environment with heavy insect activity within a few days. In the case of an exposed body, flies, maggots, ants, cockroaches, rats, dogs, jackals, vultures, etc., may reduce the body to a skeleton within a few days. When the body is in the water, it may be attacked by fish, crabs, etc., which reduces the body to a skeleton in a few days. In an uncoffined body buried in a shallow grave, putrefaction is delayed to a moderate extent. In a deeply buried body, the lower temperature, the exclusion of air, the absence of animal life, etc., markedly delay decomposition. Option: B. Adipocere- Adipocere (cire=wax) is a modification of putrefaction. In this, the fatty tissues of the body change into a substance known as adipocere. It is seen most commonly in bodies immersed in water or a damp, warm environment. Option: D. The marbling of Skin- The superficial veins, especially over the roots of the limb, thighs, sides of the abdomen, shoulders, chest and neck, are stained greenish-brown or purplish-red depending on the total amount of sulphhaemoglobin formation within the affected vessels (linear branching pattern) due to the haemolysis of red cells, which stains the wall of the vessel and infiltrates into the tissue, giving a marbled appearance (red, then the greenish pattern in skin resembling the branches of a tree)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "An accused person can be forcefully examined if requested by an investigating officer, not below the rank of sub-inspector under section ………..Cr.P.C:", "options": [{"label": "A", "text": "53", "correct": true}, {"label": "B", "text": "54", "correct": false}, {"label": "C", "text": "174", "correct": false}, {"label": "D", "text": "176", "correct": false}], "correct_answer": "A. 53", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>53 Sec 53 CRPC A person is arrested on a charge of committing an offence, and there may be reasons for believing that examining his person will provide evidence of the commission of an offence. A registered medical practitioner can examine such a person, even using reasonable force, if the examination is requested by a police officer, not below the rank of sub-inspector (or any other officer acting under his direction and in good faith).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B: 54, Cr.P.C. An arrested person, at his request, may be examined by a doctor to detect evidence in his favour. A copy of the report of such examination is to be furnished by the medical practitioner to the arrested person or the person nominated by the such arrested person. Option C & D: CrPC 174and CrPC 176 Are not related to the medical examination of the accused. Hence those three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "If informed consent with full disclosure would adversely affect a patient or cause him to refuse lifesaving treatment, a physician can exercise the:", "options": [{"label": "A", "text": "Privileged communication", "correct": false}, {"label": "B", "text": "Professional secrecy", "correct": false}, {"label": "C", "text": "Res judicata", "correct": false}, {"label": "D", "text": "Therapeutic privilege", "correct": true}], "correct_answer": "D. Therapeutic privilege", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Therapeutic privilege This is an exception to the rule of \"full disclosure\". Full disclosure of remote or theoretical risks could result in frightening a patient who is already fearful or emotionally disturbed and who may refuse the treatment when there is minimal risk. It is only in the case of frank psychosis or extreme psycho-neurosis that the patient will be incapable of accepting the information. In these cases, the doctor may use discretion regarding the facts he discloses. The doctor should carefully note his decision in the patient's record, explaining his intentions and the reasons. He should request a consultation to establish that the patient is emotionally disturbed. The presence of a malignancy or an unavoidable fatal lesion may not be disclosed if the doctor feels the patient cannot tolerate the knowledge. If possible, the physician should explain the risks to the patient's spouse or next of kin.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: PRIVILEGED COMMUNICATION: It is a statement made bonafide upon any subject matter by a doctor to the concerned authority due to his duty to protect the interests of the community or the State Option B: PROFESSIONAL SECRECY (confidentiality): It is an implied contract term between the doctor and his patient. The relationship between doctor and patient requires utmost trust, confidence, fidelity and honesty. The doctor is obliged to keep secret all that he comes to know concerning the patient during his professional work. Option C: Res judicata (S. 300, Cr.P.C.). If a Court has already decided a question of negligence against a doctor in a dispute between the doctor and his patient. The patient will not be allowed to contest the same question in another proceeding between himself and the doctor on the same set of facts. Only appeal can be made.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "While drunk, a doctor operated on a woman for eclampsia. Two days later, the woman died due to the injuries produced during the operation. The doctor was sentenced to one-year imprisonment for criminal negligence as he:", "options": [{"label": "A", "text": "Exhibited gross lack of competency/skill", "correct": true}, {"label": "B", "text": "Treated operation upon a pregnant woman", "correct": false}, {"label": "C", "text": "Is guilty of contributory negligence", "correct": false}, {"label": "D", "text": "Violated code of medical ethics", "correct": false}], "correct_answer": "A. Exhibited gross lack of competency/skill", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Exhibited gross lack of competency/skill This question wants to explore your understanding of what constitutes criminal negligence. Professional negligence (aka medical negligence) is divided into civil and criminal. By definition, criminal negligence may arise: When a doctor shows a gross absence of skill or care during treatment resulting in serious injury to or death of the patient; When a doctor performs an illegal act; When an assaulted person dies, the defence may attribute the death to negligence or undue interference in the treatment of the deceased by the doctor. In this case, as you can see, the doctor was drunk, and, at the time of the operation, there was a lack of skill, because of which the woman died. Hence it is the correct answer.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Treated operation upon a pregnant woman- This does not constitute criminal negligence as the doctor must treat eclampsia however he seems appropriate. Option: C. Is guilty of contributory negligence- The doctrine of contributory negligence comes into play in civil negligence and not criminal negligence. Option: D. Violated code of medical ethics - He violated the code of medical ethics, and the state Medical council might give him punishment as disciplinary action against the doctor.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Mrs. Kamala, a 65-year-old female patient, presents to the fever clinic with fever symptoms for 5 days, cough, mild breathlessness and body ache. Her son recently tested positive for covid-19 and is on home quarantine. The patient is an uncontrolled diabetic on irregular medication and also hypertensive. On examination, she is febrile; her pulse rate is 108 bpm, her BP- is 160/100mm Hg, and her oxygen saturation is 89%. After proning, her saturation improves to 92%. Instead of admitting the patient, the doctor on duty advises home quarantine and the prescription of paracetamol and multivitamins only. He also asks the patient to report to the hospital immediately in case of worsening symptoms or vital parameters. The patient begins home quarantine and develops tachypnea and breathlessness within 2 days. Her saturation drops to 85%, but she still refuses to report to the hospital. Within 12 hours, the patient deteriorates. Further, she becomes disoriented, agitated, tachycardic, and hypotensive; her saturation drops to 65%. She goes into ARDS and has to be intubated. The doctor cannot be held negligent under the:", "options": [{"label": "A", "text": "Medical Maloccurence", "correct": false}, {"label": "B", "text": "Therapeutic misadventure", "correct": false}, {"label": "C", "text": "Novus actus interveniens", "correct": false}, {"label": "D", "text": "Contributory negligence", "correct": true}], "correct_answer": "D. Contributory negligence", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Contributory negligence This is a case of contributory negligence since the doctor failed to admit the high-risk, moderately symptomatic patient in the first place. Second, the patient failed to report to the hospital despite the doctor's warning. Contributory negligence is any unreasonable conduct or absence of ordinary care on the part of the patient, or his attendant, which, combined with the doctor's negligence, contributed to the injury complained of as a direct, proximate cause and without which the injury would not have occurred.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A- Medical maloccurence- In some cases, despite good medical attention and care, an individual fails to respond properly or may suffer from adverse reactions to the drug. This is called medical mal occurrence. The injured person could not get monetary compensation for every mishap or accident which results in injury if the doctor was careful in the selection of ·the drug and has taken appropriate measures to overcome the undesirable foreseeable effects. Option B- Therapeutic misadventure can be defined as an injury or an adverse event caused by medical management rather than by an underlying disease. Option C- Novus actus interveniens- Sometimes, such a continuity of events is broken by an entirely new and unexpected happening due to some other person's negligence. If the doctor is negligent, which results in a deviation from the original sequence of events. then the responsibility for the subsequent disability or death may pass from the original incident to the latter negligent action by the principle of \"novus actus interveniens\" (an unrelated action intervening).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In a mass vaccination camp under the COVID vaccination drive, a doctor administered the COVISHIELD vaccine to a 46 yr. old Gym instructor. The doctor took all necessary precautions. Unfortunately, while administering the vaccine, the needle broke inside the deltoid muscle. Further treatment was ensured immediately, and the person got treated. After a few days, the gym instructor sued the doctor for damages. Which of the following will come as a defence for the doctor at the court :", "options": [{"label": "A", "text": "Res ipsa loquitor", "correct": false}, {"label": "B", "text": "Doctrine of common knowledge", "correct": false}, {"label": "C", "text": "Medical maloccurence", "correct": true}, {"label": "D", "text": "Novus actus interveniens", "correct": false}], "correct_answer": "C. Medical maloccurence", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Medical maloccurence In some cases, despite good medical attention and care, an individual fails to respond properly or may suffer from an adverse reaction to the drug, referred to as medical maloccurence. These are unseen consequences and are not in the hands of the treating physician. Breaking a needle during an I.M. injection due to sudden muscular spasm, anaphylactic reaction even the test dose of a drug are examples.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Res ipsa loquitor (things speaks for it selves) and Option: B. Doctrine of Common knowledge (doctor expected to possess common non-technical knowledge) are doctrines which prove medical negligence, hence cannot be considered as a defence, hence eliminated. Option: C. Novus actus interviniens also, most of the time, proves the negligence on the doctor's part if a decision or negligence made by him has led to a change in the normal progression of a disease into a further worse prognosis. g. the accidental substitution of a poisonous drug for a therapeutic drug.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A negligence suit was filed against a surgeon for an unexpected death of a patient. He was discussing with his lawyer about his defences. All the following can be used as a defence in a case of criminal negligence by a doctor EXCEPT:", "options": [{"label": "A", "text": "Therapeutic misadventure", "correct": false}, {"label": "B", "text": "Unforeseeable complication", "correct": false}, {"label": "C", "text": "Error of judgement", "correct": false}, {"label": "D", "text": "Contributory negligence", "correct": true}], "correct_answer": "D. Contributory negligence", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Contributory negligence Contributory negligence means negligence by the patient or a patient's caregiver in addition to the doctor’s negligence. It is a defence in only civil negligence and not in criminal negligence.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, B & C. Defences against medical negligence: No duty, adhered to standards, res judicata, therapeutic misadventure and error of judgment. Therapeutic misadventure (Medical maloccurance) is a mischance or an accident/mishap/disaster, as in the case of a penicillin injection causing anaphylaxis in a patient, administered even after a negative test dose of penicillin. Here no one is at fault; it is only a mischance.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Appeal against the Professional Death sentence after exhausting all the remedies in State Medical Council is made to:", "options": [{"label": "A", "text": "National Medical Commission.", "correct": false}, {"label": "B", "text": "High Court.", "correct": false}, {"label": "C", "text": "Supreme Court.", "correct": false}, {"label": "D", "text": "Ethics & medical registration board ( EMRB).", "correct": true}], "correct_answer": "D. Ethics & medical registration board ( EMRB).", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ethics & medical registration board ( EMRB). If the name of any person is removed from the State Medical Register, he may appeal to EMRB after exhausting all the remedies under the State Medical Council Act. Every such appeal should state the grounds of the appeal and be accompanied by all relevant documents within 30 days from the decision appealed against. The decision of the EMRB is binding on the State Government and the State Medical Council. In case of discrepancy, the final decision is taken by NMC itself.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A pregnant woman was given a full dose of a drug which had the probability of causing an anaphylactoid reaction without doing sensitivity tests. The doctor claimed therapeutic misadventure. The burden of proof is on", "options": [{"label": "A", "text": "Patient", "correct": false}, {"label": "B", "text": "Drug manufacturing company", "correct": false}, {"label": "C", "text": "Doctor", "correct": true}, {"label": "D", "text": "Does not depend on anyone since side effects are common", "correct": false}], "correct_answer": "C. Doctor", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Doctor To avoid a therapeutic misadventure in prescribing drugs, the following points should be Noted: Before prescribing any drug known to cause any adverse reaction, the doctor should make a reasonable effort to determine if any adverse reaction is likely to occur. Sensitivity tests should be done before injecting preparations likely to produce anaphylactic shock. The doctor should warn the patient of side effects, particularly possible drowsiness or similar accident-producing reaction, which may occur while taking the drug. The doctor should inform the patient about the possibility of permanent side effects.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. A physician is not liable for injuries resulting from adverse reactions to drugs unless some negligence on his part contributed to causing the injury, however, in the above question, it was the fault of the doctor for not doing the sensitivity tests. Therefore, the physician is liable, not the patient or the drug manufacturing company.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A medical practitioner sometimes needs to communicate with the authority about the patient's details. Privileged Communications means an exception to the general rule of:", "options": [{"label": "A", "text": "Professional Negligence", "correct": false}, {"label": "B", "text": "Professional Secrecy", "correct": true}, {"label": "C", "text": "Products Liability", "correct": false}, {"label": "D", "text": "The Doctrine of Res Ipsa Loquitor", "correct": false}], "correct_answer": "B. Professional Secrecy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Professional Secrecy Privileged communication, in other words, means exceptions to the general rule of professional secrecy. It is a statement made bonafide upon any subject matter by a doctor to the concerned authority due to his duty to protect the interests of the community or the State. To be privileged, communication must be made to a person interested in it or about which he has a duty. If made to more than one person or a person who has no direct interest in it, the plea of privilege fails.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D. Professional Negligence, Products Liability or doctrine of Res Ipsa Loquitor is not related to privileged communication. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient filed a negligence case against a doctor as the doctor could not cure his carcinoma. In civil negligence, the onus to prove lies on:", "options": [{"label": "A", "text": "First-class judicial magistrate", "correct": false}, {"label": "B", "text": "Doctor", "correct": false}, {"label": "C", "text": "Police officer not less than the rank of sub-inspector", "correct": false}, {"label": "D", "text": "Patient", "correct": true}], "correct_answer": "D. Patient", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Patient The burden of proving civil negligence lies on the plaintiff (patient). The burden of proof is the need or duty to establish proof of the facts at trial. To establish negligence, it is not necessary to prove that the negligent party had a bad motive or intention. The essential issue that decides a case of negligence is whether a reasonably competent medical man would have acted more or less the same manner the doctor against whom negligence is alleged had acted. The burden of proof: The patient should prove all four elements of civil negligence by a preponderance of the evidence. It requires enough proof to show that it is more likely than not that each of the 4 elements of a negligent claim is true.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A, B & C: First Class Magistrate and Police officer are unrelated to it, while the onus of proof lies on a doctor in a criminal negligent suit. Hence these options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 25-year-old lady died due to some unnatural cause within 7 years of her marriage. The inquest should be done under:", "options": [{"label": "A", "text": "174 Cr. P.C", "correct": false}, {"label": "B", "text": "176 Cr. P.C", "correct": true}, {"label": "C", "text": "304 IPC", "correct": false}, {"label": "D", "text": "304 B IPC", "correct": false}], "correct_answer": "B. 176 Cr. P.C", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>176 Cr. P.C S-176, Cr. C: Any person dies or disappears, or rape is alleged to have been committed on any woman, while such person or woman is in the custody of the police or any other custody authorised by the magistrate or the court, under this code in addition to the inquiry or investigation held by the police, an inquiry shall be held by the judicial magistrate or the metropolitan magistrate.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. 174 Cr.C. is Police Inquest which is not applicable here. Option: C. 304 IPC is punishment for culpable homicide not amounting to murder. Option: D. 304 B IPC is punishment for dowry death and not for the inquest to be conducted 304 A IPC deals with causing death by negligence</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Inquest under CrPC 174 can be done by a police officer, not below the ranking of:", "options": [{"label": "A", "text": "Inspector", "correct": false}, {"label": "B", "text": "Sub-inspector", "correct": false}, {"label": "C", "text": "PSHO", "correct": false}, {"label": "D", "text": "Head constable", "correct": true}], "correct_answer": "D. Head constable", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Head constable Police inquest is done by a police officer not less than the rank of head constable.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B & C : Since the lowest rank to conduct a police inquest is Head Constable, all other options cannot be the lowest rank. Hence are wrong</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A medical examiner got a call regarding a suspected homicide in Ottawa, Canada. He examined the crime scene, collected evidence and prepared the initial investigation report and handed it over to the related authorities.Which of the following is true about the above situation :", "options": [{"label": "A", "text": "The Medical Examiner has the authority to order the arrest of any person.", "correct": false}, {"label": "B", "text": "The Medical Examiner has all the judicial functions of a Coroner.", "correct": false}, {"label": "C", "text": "This system is widely practised in India.", "correct": false}, {"label": "D", "text": "This type of inquest is superior to both Coroners and Police inquests.", "correct": true}], "correct_answer": "D. This type of inquest is superior to both Coroners and Police inquests.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>This type of inquest is superior to both Coroners and Police inquests. The medical examiner system is the above-mentioned type of inquest.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: C. It is common in the US, Canada, and Japan but not practised in India. A doctor is assigned as a Medical examiner and can carry out the initial investigation. Option: B. But he doesn’t possess any judicial powers unlike the Coroner and can’t issue arrest of any person. (Option A) Option: D. As the doctor himself is visiting the scene of the crime, it is superior to both Coroners and Police inquest.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Ram, an experienced forensic surgeon was informed by the police that an unidentified body was found at Chilapata forest, West Bengal, today early morning and they asked him to get it autopsied. Ram requested the IO not to move the body from its original position until he comes and inspects it. Ram's assistant overheard this conversation and asked him why he was insisting on going there instead of waiting in the autopsy room. Which of the following would NOT be a rationale behind this action by Ram :", "options": [{"label": "A", "text": "Since Medical Examiner’s inquest is superior to a Police inquest.", "correct": true}, {"label": "B", "text": "To avoid fresh tears in the corpse’s clothes due to rough handling.", "correct": false}, {"label": "C", "text": "To avoid forming incorrect opinions about the origin of various injuries in the body.", "correct": false}, {"label": "D", "text": "Since there are chances of production of fresh abrasions while transferring to the mortuary.", "correct": false}], "correct_answer": "A. Since Medical Examiner’s inquest is superior to a Police inquest.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Since Medical Examiner’s inquest is superior to a Police inquest. In the question, it is mentioned as the Chilapata forest, which is in West Bengal, India. The Medical Examiner system is not followed in India, so that can’t be the answer.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- All the other points are reasons for a doctor to visit the crime scene. If the doctor sees the dead body for the first time in the autopsy room, then there are pretty good chances of him making an incorrect opinion about the origin of injuries. Seeing the dead body at the scene of the crime will help to avoid such mistakes and can avoid further production of injuries while transporting.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A medical examiner got a call regarding a suspected homicide in Ottawa, Canada. He examined the crime scene, collected evidence and prepared the initial investigation report and handed it over to the related authorities. Which of the following is true about the above situation:", "options": [{"label": "A", "text": "The Medical Examiner has the authority to order the arrest of any person.", "correct": false}, {"label": "B", "text": "The Medical Examiner has all the judicial functions of a Coroner.", "correct": false}, {"label": "C", "text": "This system is widely practised in India.", "correct": false}, {"label": "D", "text": "This type of inquest is superior to both Coroners and Police inquests.", "correct": true}], "correct_answer": "D. This type of inquest is superior to both Coroners and Police inquests.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>This type of inquest is superior to both Coroners and Police inquests. The medical examiner system is the above-mentioned type of inquest. As the doctor himself is visiting the scene of the crime, it is superior to both Coroners and Police inquest.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: C. It is common in the US, Canada, and Japan but not practised in India. A doctor is assigned as a Medical examiner and can carry out the initial investigation. Option: B. But he doesn't possess any judicial powers unlike the Coroner Option: A. and can't issue an arrest of any person.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Type of inquest which will be happening in the following incident", "options": [{"label": "A", "text": "Coroner's inquest", "correct": false}, {"label": "B", "text": "Magistrate's inquest", "correct": true}, {"label": "C", "text": "Police inquest", "correct": false}, {"label": "D", "text": "Medical Examiner’s inquest", "correct": false}], "correct_answer": "B. Magistrate's inquest", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892348799-QTDF022009IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Magistrate's inquest Magistrate’s inquest is followed in cases of death due to police firing, death or rape in custody, dowry deaths, exhumation etc. Judicial magistrate conducts inquest into Death in police custody, and while under police interrogation, Death due to police firing, Death in prison, reformatories, Borstal school, Death in a psychiatric hospital, Dowry deaths, and Any person dies or disappears, or rape is alleged to have been committed on any woman, while such person or woman is in the custody of the police or any other custody authorised by the court. 176 Cr.P.C. (1A). Inquest by the executive magistrate is done in death in a mental asylum, dowry death, and exhumation. 176 CrPC</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: C. In a Police inquest, the officer in charge of the police station conducts the inquest, he is the investigating officer. When the officer in charge of the police station receives information that a person has committed suicide or killed by someone or died under the circumstances raising a reasonable suspicion, he immediately gives intimation about it to the nearest executive magistrate empowered to hold an inquest and proceed to the place where the body of such a deceased person is. 174 CrPC Option: A. Coroner's inquest is a type of inquest done in the UK and some other countries but not in India. coroner conducts inquest in all unnatural and suspicious death. The doctor is summoned to his court to give evidence at the inquest. Coroner’s court is a court of enquiry. He has judicial powers. Option: D. The medical examiner's system is practised in the USA, Canada, and Japan but not in India. An inquest is conducted by a medical person but he does not have any judicial power. It is the best type of interest overall.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Ram, an experienced forensic surgeon was informed by the police that an unidentified body was found at Chilapata forest, West Bengal, today early morning and they asked him to get it autopsied. Ram requested the IO not to move the body from its original position until he comes and inspects it. Ram's assistant overheard this conversation and asked him why he was insisting on going there instead of waiting in the autopsy room. Which of the following would NOT be a rationale behind this action by Ram :", "options": [{"label": "A", "text": "Since Medical Examiner’s inquest is superior to a Police inquest.", "correct": true}, {"label": "B", "text": "To avoid fresh tears in the corpse’s clothes due to rough handling.", "correct": false}, {"label": "C", "text": "To avoid forming incorrect opinions about the origin of various injuries in the body.", "correct": false}, {"label": "D", "text": "Since there are chances of production of fresh abrasions while transferring to the mortuary.", "correct": false}], "correct_answer": "A. Since Medical Examiner’s inquest is superior to a Police inquest.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Since Medical Examiner’s inquest is superior to a Police inquest. In the question, it is mentioned as the Chilapata forest, which is in West Bengal, India. The Medical Examiner system is not followed in India, so that can't be the answer. All the other points are reasons for a doctor to visit the crime scene. If the doctor sees the dead body for the first time in the autopsy room, then there are pretty good chances of him making an incorrect opinion about the origin of injuries. Seeing the dead body at the scene of the crime will help to avoid such mistakes and can avoid further production of injuries while transporting.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C & D. There are some disadvantages of the doctor not visiting the scene: When the body is transferred to the mortuary fresh abrasions may be produced on it during transit, Clothing will be disarranged, blood stains will form on parts of the clothes originally free from them, Fresh tears in clothes may be produced from rough handling, Existing rigour mortis may be broken down at least partially.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A police officer can arrest a person without a warrant from the magistrate for involvement in all of the following cases except:", "options": [{"label": "A", "text": "Causing death by rash & negligent act", "correct": false}, {"label": "B", "text": "Perjury", "correct": true}, {"label": "C", "text": "Molestation", "correct": false}, {"label": "D", "text": "Causing miscarriage without woman’s consent", "correct": false}], "correct_answer": "B. Perjury", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Perjury Among the following options given, Perjury is not a cognisable offence. Hence cannot be arrested without a warrant from the magistrate.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D Others are an offence in which a police officer can arrest a person without a warrant from the magistrate, e.g., rape, murder, dowry death, ragging, death due to rash or negligent acts, etc. These are cognisable offences</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "As per _________CrPC, If a woman sentenced to death is found to be pregnant, the High Court shall commute the sentence to imprisonment for life:", "options": [{"label": "A", "text": "416", "correct": true}, {"label": "B", "text": "417", "correct": false}, {"label": "C", "text": "419", "correct": false}, {"label": "D", "text": "418", "correct": false}], "correct_answer": "A. 416", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>416 When a woman is sentenced to death, pleads that she is pregnant, to avoid execution. The High Court has the power to commute it (S.416, Cr.P.C.)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "As per _________IEA, In a prosecution for rape, where sexual intercourse by the accused is proved and such a woman states that she did not consent, the court shall presume that she did not consent:", "options": [{"label": "A", "text": "114A", "correct": true}, {"label": "B", "text": "115", "correct": false}, {"label": "C", "text": "113A", "correct": false}, {"label": "D", "text": "116A", "correct": false}], "correct_answer": "A. 114A", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>114A 114A, I.E.A: In a prosecution for rape, where sexual intercourse by the accused is proved and the question is whether it was without the consent of the woman alleged to have been raped and such woman states in her evidence before the court that she did not consent, the court shall presume that person did not consent.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C & D. are not related to the presumption of consent by the female</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A pregnant lady went to a local medical man for an abortion. She was pregnant for 20 weeks and was unmarried. Assisting criminal abortion victims is punishable under the IPC section:", "options": [{"label": "A", "text": "312", "correct": true}, {"label": "B", "text": "314", "correct": false}, {"label": "C", "text": "313", "correct": false}, {"label": "D", "text": "315", "correct": false}], "correct_answer": "A. 312", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>312 Under Sec. 312, I.P.C. whoever voluntarily causes criminal abortion is liable for imprisonment up to three years, and/or a fine; and if the woman is quick with the child the imprisonment may extend up to seven years. It is necessary that the woman should be pregnant and that abortion should be carried out with her consent. Both the person causing the abortion and the woman are liable for punishment. If the means used do not succeed, it is punishable under Sec.511, I.P.C. with imprisonment up to half of the punishment under Sec.312.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Under Sec. 314, if a pregnant woman dies from an act intended to cause miscarriage, the offender is liable to be punished with rigorous imprisonment which shall not be less than ten years and also a fine of up to two lakh rupees. Provided that if the miscarriage is caused after conducting a pre-natal sex determination test of the foetus confirming it to be a female foetus, the person causing the miscarriage shall be punished with rigorous imprisonment for life and shall also be liable to a fine which may extend to two lakh rupees. Option: C. Under Sec. 313, if the miscarriage is caused without the consent of the woman, the imprisonment may be up to ten years. If a miscarriage of a female foetus is caused after a pre-natal sex determination test, the accused shall be punished with imprisonment for life and shall also be liable to a fine which may extend to two lakh rupees. Option: D. Under Sec. 315, a person doing an act intended to prevent the child from being born alive or to cause it to die after its birth is liable to be punished with imprisonment for up to ten years. If the offence referred to in subsection (1) is committed after conducting a prenatal sex determination test confirming a female foetus, the person committing such an offence shall be punished with rigorous imprisonment for life and shall be liable to a fine which may extend to two lakh rupees.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "If a person keeps a man under his power and threatens him to cause harm without any intention to kill comes under which section of IPC:", "options": [{"label": "A", "text": "IPC 44", "correct": false}, {"label": "B", "text": "IPC 351", "correct": true}, {"label": "C", "text": "IPC 319", "correct": false}, {"label": "D", "text": "IPC 320", "correct": false}], "correct_answer": "B. IPC 351", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>IPC 351 S. 351, I.P.C.: An assault is an offer or threat or attempt to apply force to the body of another in a hostile manner. It may be a common assault or with an intent to murder. S.352 to 3581. C. deal with punishments for various types of assaults. (to review).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. 44 I.P.C: INJURY: Any harm whatever illegally caused to any person in body, mind, reputation or property Option: C. 319 I.P.C.: HURT: Hurt means bodily pain, disease or infirmity caused to any person. It does not include mental pain Option: D. 320 I.P.C gives the Definition of Grievous Hurt</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 22 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A dead born fetus was delivered after two days. The fetus was macerated. The earliest sign of Maceration:", "options": [{"label": "A", "text": "Spalding Sign", "correct": false}, {"label": "B", "text": "Robert Sign", "correct": false}, {"label": "C", "text": "Skin Slippage", "correct": true}, {"label": "D", "text": "Overcrowding of Ribs", "correct": false}], "correct_answer": "C. Skin Slippage", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Skin Slippage The earliest sign of maceration is the reddening of the skin with peeling and slippage, which can be seen 12 hours after the death of the child in utero.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Gas in great vessels (aorta in 12 hours) of fetus indicates fetal death (Robert's sign). Option: A & D. SPALDING'S SIGN: Loss of alignment and overriding of the bones of the cranial vault occur due to shrinkage of the cerebrum after the death of the fetus. In the early stage, there is only a loss of alignment without overriding. The sign will develop earlier with a vertex presentation than with a breech. It may be detected within a few days of the death of the fetus, but often takes much longer time, sometimes even two to three weeks.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A pregnant lady with three living girl children delivers a baby girl again in her 4th pregnancy too. Annoyed with the fourth girl in the family, her husband and in-laws leave the mother alone and go away. 12 hours after the delivery, the lady complains that her baby is not responding. Doctors examine the baby and declare it to be dead. The lady dramatizes that the doctors delivered a dead born baby but in fact, the lady had killed her baby because it was a girl baby. The case was registered at the police station. The autopsy of the baby may show all of the following except.", "options": [{"label": "A", "text": "Diaphragm is found at the level of the sixth rib", "correct": false}, {"label": "B", "text": "Chest is arched or drum shaped", "correct": false}, {"label": "C", "text": "Stomach and intestine float in water", "correct": false}, {"label": "D", "text": "The lung margins are sharp", "correct": true}], "correct_answer": "D. The lung margins are sharp", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The lung margins are sharp If the baby died in utero and no signs of live birth were present at delivery, then the margins of the lung are sharp, which become rounded even when the breathing is feeble. In a minimally respired lung, the anterior margin shows partial expansion; the lingula, anterior or diaphragmatic margin, and medial edge of the lower lobe are sometimes pinker and more expanded than the posterior parts. Glistening bullae appear along the margins when there has been a struggle to breathe due to some mechanical obstruction.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. The Position of the Diaphragm: The abdomen should be opened before the thorax, and the highest point of the diaphragm is noted, which is found about the level of the fourth or fifth rib if respiration has not taken place, and at the level of the sixth or seventh rib after breathing. The position is affected by gases of decomposition. Option: B. The shape of the Chest: Before respiration, the chest is flat and its circumference is one to two cm. less than the abdomen at the level of the umbilicus. After respiration, the chest expands and becomes arched or drum-shaped. Option: C. Changes in the Stomach and Intestines: - Air is swallowed into the stomach during respiration. Hence, the stomach and intestines are removed after tying double ligatures at each end. They float in water if respiration has taken place, otherwise, they sink. This is known as Breslau's second life test or stomach-bowel test. This test is not of much value because air may be swallowed by the child in attempting to free the air passages of fluid obstructions in cases of stillbirth. It is useless when there is decomposition. In a stillborn child or one dying shortly after birth. The stomach will contain grey-white gastric mucin mixed with swallowed amniotic fluid. Sometimes, the infant may swallow maternal blood during delivery. When dissected underwater, the stomach shows mucus, saliva, and air bubbles if respiration has taken place, and only mucus if breathing has not occurred. Blood, meconium, or liquor amnii in the stomach indicates that the child was alive at or shortly before birth. If milk is present in the stomach, it is positive evidence that the child has lived for some time after birth.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The spalding sign is seen with:", "options": [{"label": "A", "text": "Live-born Fetus", "correct": false}, {"label": "B", "text": "Dead-born Fetus", "correct": true}, {"label": "C", "text": "Still-born Fetus", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "B. Dead-born Fetus", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Dead-born Fetus SPALDING'S SIGN: Loss of alignment and overriding of the bones of the cranial vault occur due to shrinkage of the cerebrum after the death of the fetus. In the early stage, there is only a loss of alignment without overriding. The sign will develop earlier with a vertex presentation than with a breech. It may be detected within a few days of the death of the fetus, but often takes much longer time, sometimes even two to three weeks.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C, & D: Spalding Sign is not associated with a Live born or a Still Born Fetus.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A fetus was brought for autopsy. According to the police, it was recovered from a dustbin. Police requested an autopsy to know whether the child was born alive and for DNA sampling. Which body cavity is opened first in the autopsy of a newborn Fetus?", "options": [{"label": "A", "text": "Cranial cavity", "correct": false}, {"label": "B", "text": "Chest cavity", "correct": false}, {"label": "C", "text": "Abdominal cavity", "correct": true}, {"label": "D", "text": "Pelvic cavity", "correct": false}], "correct_answer": "C. Abdominal cavity", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Abdominal cavity The abdominal cavity is to be opened before the thorax while doing an autopsy to know the level of the diaphragm.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B, & D. Cranial cavity, chest cavity, and Pelvis are opened later in the process of Autopsy only after the abdominal cavity.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The hydrostatic test is one of the tests done on the lungs of a fetus to know whether the fetus respired before death. For the hydrostatic test to be positive at all stages, the following volume of air must be present inside lung alveoli:", "options": [{"label": "A", "text": "Residual air", "correct": true}, {"label": "B", "text": "Tidal air", "correct": false}, {"label": "C", "text": "Exudates & tidal air", "correct": false}, {"label": "D", "text": "Amniotic fluid & tidal air", "correct": false}], "correct_answer": "A. Residual air", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Residual air The hydrostatic test is done in a case of infanticide and is based on the principle that the specific gravity of the unrespired lungs varies from 1.04 to 1.05 and that of respired lungs is 0.94, because of an increase in volume due to inhalation of air. The fetal lungs, therefore, sink in water and those that have respired float. Remove the lungs as far as the trachea along with the larynx by tying at the laryngeal end and placing them in a jar of water and note for their floatation. The lungs are then separated and each is tested separately for the presence or absence of floatation. Finally, each lung is then cut into fragments that are again tested for floatation. If in all such events, floatation is present the test is positive (provided putrefaction is absent). If they continue to float even after this compression due to the presence of residual air, the test is positive and respiration has taken place. If some of the pieces sink and some float, it shows feeble respiration owing to the partial penetration of the air.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. If there is some decomposition, then the fragments should be compressed to remove the tidal air. The fragments are again placed in water.) Option: C & D. Amniotic fluid and exudates always tend to sink the lungs. Hence gives a negative hydrostatic test</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A woman comes to the obstetrician for pregnancy termination. She is 16-year-old. The minimum age for medical termination of pregnancy is:", "options": [{"label": "A", "text": "16 Years", "correct": false}, {"label": "B", "text": "18 Years", "correct": true}, {"label": "C", "text": "20 Years", "correct": false}, {"label": "D", "text": "24 Years", "correct": false}], "correct_answer": "B. 18 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>18 Years Salient features of the MTP Act, 2021:- Consent of woman is required, consent of the husband is not required Consent of the guardian if the woman is a minor is required, professional secrecy is to be maintained pregnancy. < 20 weeks - a single doctor can terminate the 20 – 24 weeks - two doctors must be available. Pregnancy can be terminated even after 24 weeks but in the opinion of a medical board This is a very liberal act, both for the woman and the doctor (provided the doctor has exercised reasonable care & skill).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A fetus was delivered dead after the pregnant lady was assaulted by her husband and in-laws as it was a girl. For the charge sheet, police inquired whether the child is viable or not as the punishment is different. A fetus is considered viable at which of the following month of intrauterine life:", "options": [{"label": "A", "text": "5th", "correct": false}, {"label": "B", "text": "6th", "correct": false}, {"label": "C", "text": "7th", "correct": true}, {"label": "D", "text": "8th", "correct": false}], "correct_answer": "C. 7th", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>7th The viability- of an infant is at 28 weeks (end of 7thi.u. months) or 210 days of intrauterine life.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Ossification center for Calcaneum- 5th i.u. month. Talus- 7th i.u. month. Lower end femur- birth. Cuboid- just after birth. Deadborn- is a child who died inside the uterus and shows signs such as maceration, Spalding’s sign, Robert’s sign, rigor mortis, and mummification after it is completely born.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A pregnant lady came to prenatal care with a complaint of not feeling the movement of the fetus yet. She is 18 weeks pregnant. Quickening is felt by the mother during the following period of pregnancy:", "options": [{"label": "A", "text": "10 - 12 weeks", "correct": false}, {"label": "B", "text": "12 - 16 weeks", "correct": false}, {"label": "C", "text": "16 - 20 weeks", "correct": true}, {"label": "D", "text": "20 - 24 weeks", "correct": false}], "correct_answer": "C. 16 - 20 weeks", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>16 - 20 weeks Quickening(16-20 weeks)-quickening is the moment in pregnancy when the pregnant woman starts to feel or perceive fetal movements in the uterus.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B, & D. are not significant regarding quickening.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A hydrostatic test is a test done to test the lungs. A hydrostatic test is performed in a the case of:", "options": [{"label": "A", "text": "Hanging", "correct": false}, {"label": "B", "text": "Drowning", "correct": false}, {"label": "C", "text": "Infanticide", "correct": true}, {"label": "D", "text": "Firearm", "correct": false}], "correct_answer": "C. Infanticide", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Infanticide Hydrostatic test: Raygat’s test:- It is a test done for infanticide:- Specific gravity: Before respiration=1050, After respiration=940 The liver is used as a control, if the liver also floats test is of no value. False positive: unexpanded lung may float due to the following reasons- Presence of putrefactive gases Artificial respiration False negative: expanded lung may sink due to the following reasons Atelectasis Acute edema of the lung</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B & D: Hydrostatic test is not used in hanging, drowning. or firearm.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A hydrostatic test is a test done to test the lungs. A false positive hydrostatic test is associated with:", "options": [{"label": "A", "text": "Atelectasis", "correct": false}, {"label": "B", "text": "Artificial respiration", "correct": true}, {"label": "C", "text": "Pneumonia", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "B. Artificial respiration", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Artificial respiration Hydrostatic test: Raygat’s test:- It is a test done for infanticide Specific gravity: Before respiration=1050, After respiration=940 The liver is used as a control, if the liver also floats test is of no value. False positive: unexpanded lung may float due to Presence of putrefactive gases Artificial respiration</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A & C. False negative: expanded lung may sink due to Atelectasis Acute edema of the lung Pneumonia</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 35-year-old chronic alcoholic assumes that he is very damn and owns all the luxurious cars and a bungalow. He keeps telling people about the assets he owns but in reality, he is a pauper. This is", "options": [{"label": "A", "text": "Delusion of exaltation", "correct": true}, {"label": "B", "text": "Delusion of infidelity", "correct": false}, {"label": "C", "text": "Nihilistic delusion", "correct": false}, {"label": "D", "text": "Both A and C", "correct": false}], "correct_answer": "A. Delusion of exaltation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Delusion of exaltation Delusion of Grandeur or exaltation: A man Imagines himself to be very rich while in reality, he is a pauper. They are seen in delirium tremens.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Delusion of Infidelity:- man imagines his wife to be unfaithful while in fact, she is chaste. Option: C & D. Nihilistic delusion: The person declares that he does not exist or that there is no world, etc.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 60-year-old schizophrenic person forgets his own life, leaves his home and wanders to a new place. This is called", "options": [{"label": "A", "text": "Dissociative fugue", "correct": true}, {"label": "B", "text": "Dissociative amnesia", "correct": false}, {"label": "C", "text": "Both A and B", "correct": false}, {"label": "D", "text": "Dissociative identity disorder", "correct": false}], "correct_answer": "A. Dissociative fugue", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Dissociative fugue Dissociative fugue:- A state of altered awareness during which an individual forgets part or whole of his life, leaves home and wanders. It may occur in hysteria, depressive illness, schizophrenia and epilepsy.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C. Dissociative amnesia is a type of dissociative disorder that involves the inability to recall important personal information that would not typically be lost with ordinary forgetting. It is usually caused by trauma or stress. Diagnosis is based on history after ruling out other causes of amnesia Option: D. Dissociative identity disorder is characterised by the presence of two or more distinct personality identities. Each may have a unique name, personal history and characteristics.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Magnan’s symptom is:", "options": [{"label": "A", "text": "Illusion", "correct": false}, {"label": "B", "text": "Delusion", "correct": false}, {"label": "C", "text": "Formication", "correct": true}, {"label": "D", "text": "Depersonalization", "correct": false}], "correct_answer": "C. Formication", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Formication Magnan's symptom or cocaine bugs is characteristic of cocaine addicts in which there is a feeling as if grains of sand are lying under the skin or some small insects are creeping on the skin giving rise to itching sensation (formication, tactile hallucination) with resultant excoriation, leading to irregular scratches and ulcers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "MOA of Cocaine is:", "options": [{"label": "A", "text": "It acts by increasing the concentrations of Dopamine, Norepinephrine and Serotonin in the synapses.", "correct": true}, {"label": "B", "text": "It acts by binding to anandamide receptors in the brain causing stimulant, sedative or hallucinogenic actions which are dose-dependent.", "correct": false}, {"label": "C", "text": "It acts by blocking acetylcholine receptors.", "correct": false}, {"label": "D", "text": "It acts by catecholamine release and inhibition of sympathetic reflexes.", "correct": false}], "correct_answer": "A. It acts by increasing the concentrations of Dopamine, Norepinephrine and Serotonin in the synapses.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>It acts by increasing the concentrations of Dopamine, Norepinephrine and Serotonin in the synapses. Cocaine is an odourless, crystalline substance with a bitter taste and is slightly soluble in water. Cocaine increases the concentration of these neurotransmitters by binding to transporter proteins in presynaptic neurons and blocking uptake. It is a local anaesthetic act by blocking nerve impulse initiation and conduction by decreasing axon permeability to Na+ ions. It is the only LA which is a sympathomimetic It causes stimulation followed by depression. Cocaine acts by increasing the concentration of neurotransmitters like Dopamine, Norepinephrine, and</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Cannabis acts by THC (Tetrahydrocannabinol) binding to anandamide receptors in the brain causing stimulant, sedative or hallucinogenic actions which are dose-dependent and also depend on time after consumption. Option: C. Datura acts by blocking acetylcholine receptors as it contains atropine and hyoscine and produces sympathomimetic action. Option: D. Cannabis acts by catecholamine release and inhibition of sympathetic reflexes leading to tachycardia and orthostatic hypotension respectively.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 44 years old female presented to Medicine OPD with complaints of dysphagia, drunken gait, diplopia, dimness of vision, dryness of mouth and pin rolling movements of fingers. She was a chronic substance abuser. The active principle of the substance abused is -", "options": [{"label": "A", "text": "Hyoscine", "correct": true}, {"label": "B", "text": "THC", "correct": false}, {"label": "C", "text": "Alkaloid ecgonine", "correct": false}, {"label": "D", "text": "LSD", "correct": false}], "correct_answer": "A. Hyoscine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hyoscine The features mentioned above- Dysphagia, diplopia, dimness of vision, and dryness of mouth comprise 8D’s of Datura poisoning. 8D’s: Dryness of mouth, Dysphagia, Dilated pupils, Dry and hot skin, Drunken gait, Delirium, Drowsiness, Death. Datura contains- Hyoscine, atropine, and hyoscyamine as its active principals. It has anticholinergic actions so the above-mentioned features were seen. Hyoscine is the active principle in Datura.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B. THC tetrahydrocannabinol is the active ingredient of Cannabis. Cannabis is a stimulant of CNS and doesn't have anticholinergic action. Option C. Alkaloid ecgonine is the active principle of Cocaine. Cocaine acts as a local anaesthetic and causes stimulation followed by depression of CNS. Option D. LSD Lysergic Acid Diethylamide is a colourless, tasteless, odourless compound that acts by mimicking a powerful antagonist of Serotonin. It is most often implicated agent in bad trips</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 26-year-old college student presents to ER of a hospital with feelings of Euphoria, increased appetite and thirst, ataxia, and feeling that he could fly from high windows after he inhaled a drug at a party. He has started feeling that his genitalia has retracted into his abdomen. What drug did he abuse?", "options": [{"label": "A", "text": "Datura", "correct": false}, {"label": "B", "text": "Weed", "correct": true}, {"label": "C", "text": "Cocaine", "correct": false}, {"label": "D", "text": "Alcohol", "correct": false}], "correct_answer": "B. Weed", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Weed Weed is a CNS stimulant having the characteristic feature of koro-genitalia The 3 E’s - Euphoria, Emotional instability and Erotic feeling are features of Cannabis Poisoning. Cannabis is a CNS stimulant so gives the feeling of distortion to perception in which the user feels that they could fly from high windows and stop moving buses with their bare hands. Koro- The male user complains that his penis is being retracted into the abdomen. It is a culture-bound Cannabis is also used in the form of Ganja. Ganja is prepared from the flower tops of the female plant and has rusty green colour and a characteristic odour. Ganja is also known as Pot, Weed, Grass, marijuana, and</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. Datura is an anticholinergic action having poison not having the above-mentioned Option C. Cocaine is a CNS stimulant followed by a CNS depressant. Option D. Alcohol doesn't cause the feeling of genitalia retraction.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The clinical features of Cannabis abuse are:- Sinsemilla is an unpollinated flower top from a female plant. The fatal period of cannabis toxicity is 10 hrs. The person is held responsible for his acts since ‘run amok’ is not considered a disorder of the mind. Active principal is 9- tetrahydrocannabinol. Select the correct answer from given below code:-", "options": [{"label": "A", "text": "1,2,3,4", "correct": false}, {"label": "B", "text": "1,3", "correct": false}, {"label": "C", "text": "2,3,4", "correct": false}, {"label": "D", "text": "1,4", "correct": true}], "correct_answer": "D. 1,4", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,4 Sinsemillia is an unpollinated or unfertilized flower top from the female plant. It contains 6-11% THC. The fatal dose of Bhang is 10g/kg body wt. The fatal dose of Charas is 2g. The fatal dose of Ganja is 8g. The fatal period of Cannabis poisoning is 12hrs. The person is not held responsible for his acts since ‘run amok’ is considered a disorder of mind and not intoxication, unless he had taken it purposefully to strengthen himself before commissioning of offence. The active principle is a fat-soluble oleoresin - delta 9 Tetrahydrocannabinol THC which acts by binding to anandamide receptors in the brain which is one of the pathways of pain relief</p>\n<p><strong>Random:</strong></p><p>Explanation For All Options:- Option: A. 2,3 are wrong statements. Option: B. 3 is a wrong statement. Option: C. 2,3 are wrong statements. Option: D. 1,4 are correct statements.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The fatal Dose incorrectly matched is-", "options": [{"label": "A", "text": "Charas - 2g", "correct": false}, {"label": "B", "text": "Ganja - 8g", "correct": false}, {"label": "C", "text": "Bhang - 12g/kg wt", "correct": true}, {"label": "D", "text": "Cocaine - 1g", "correct": false}], "correct_answer": "C. Bhang - 12g/kg wt", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Bhang - 12g/kg wt Cannabis is abused in various forms like Ganja, Bhang, Majoon, and Charas- resin exuding from the leaves and stems of the plants and it contains 25-40% of the active principle. Its fatal dose is 2g. Ganja - prepared from flower tops of the female plant having 15-25% of the active principle. Its fatal dose is 8g. Bhang - prepared from dried leaves and fruit shoots, used to prepare decoction containing 15% of the active principle. Its fatal dose is 10g/kilo body weight. Cocaine is obtained from the leaves of Erythroxylum coca. Leaves contain 0.5-1% cocaine. The fatal dose is 1g orally, procaine is about half as toxic as cocaine. Bhang has a fatal dose of 10g/kg wt. So this is the answer because an incorrect match was asked.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Charas or Hashish has a fatal dose of 2g. Option: B. Ganja has a fatal dose of 8g. Option: D. Cocaine has a fatal dose of 1g.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "All of the following are different forms of marijuana except?", "options": [{"label": "A", "text": "Ganja", "correct": false}, {"label": "B", "text": "Bhang", "correct": false}, {"label": "C", "text": "Charas", "correct": false}, {"label": "D", "text": "Afeem", "correct": true}], "correct_answer": "D. Afeem", "question_images": [], "explanation_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/"], "explanation": "<p><strong>Solution:</strong></p><p>Afeem Others are a form of Cannabis, a CNS stimulant. It is variously known as pot, grass, dope, ganja, weed, hash, Mary Jone, M.J., hashish or bhang. It is a psychoactive drug The main active component is THC, tetrahydrocannabinol.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 20yr old boy attended a rave party 6hrs before and now presents to the ED with dilated pupils, tachycardia, hypertension and delirium. His friend gives a history that the patient took a Blue coloured pill called \"HEAVENLY BLUE\" at the party. Now the patient shows extreme mood swings and feels like seeing smells. Identify the drug causing these symptoms :", "options": [{"label": "A", "text": "LSD", "correct": true}, {"label": "B", "text": "THC", "correct": false}, {"label": "C", "text": "Gunja", "correct": false}, {"label": "D", "text": "Phencyclidine", "correct": false}], "correct_answer": "A. LSD", "question_images": [], "explanation_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/"], "explanation": "<p><strong>Solution:</strong></p><p>LSD LSD (lysergic acid diethylamide) HEAVENLY BLUE name, Blue pill, features of Synaesthesia or sensory misinterpretations (seeing smells, hearing colours), and sympathetic symptoms all point towards a hallucinogen like LSD. The colourless, odourless, tasteless semisynthetic compound obtained from Claviceps purpura. It shows both sympathetic and parasympathetic features along with synaesthesia and severe mood alterations. LSD act via the serotonin system and tropane alkaloids (parasymp). There is psychic dependence only and no abstinence syndrome. Features may persist for 12 to 18 hrs.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option: B. THC (tetra hydro cannabinol) – is the active ingredient of Cannabis, and may produce similar features but is not available in a pill form, hence eliminated. Option: C. Gunja – another name for Abrus precatorius , active ingredient: Abrin, GI symptoms predominate on acute ingestion, not similar to the above-mentioned scenario, hence eliminated. Option: D. Phencyclidine - also a hallucinogenic drug like LSD, but usually smoked or injected, it is commonly called Angel dust, hence eliminated.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Police recovered a body from a river. They were asking to know whether the person drowned himself or it was disposed of. The reliable signs of drowning at autopsy are all except", "options": [{"label": "A", "text": "Fine, white froth at the mouth and nose", "correct": false}, {"label": "B", "text": "The presence of weed, sand etc firmly grasped in the hand", "correct": false}, {"label": "C", "text": "The presence of a large amount of blood in the stomach and intestine", "correct": true}, {"label": "D", "text": "The presence of fine froth in lungs and hair passages.", "correct": false}], "correct_answer": "C. The presence of a large amount of blood in the stomach and intestine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The presence of a large amount of blood in the stomach and intestine</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- The reliable signs of drowning at autopsy are: Option: A. Fine, white froth at the mouth and nose. Option: B. The presence of weeds, sand, mud, etc., firmly grasped in the hands. The presence of fine froth in the lungs and air-passages. Option: D. The voluminous water-logged lungs. The presence of water in the stomach and intestines, and The finding of diatoms in the tissues.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Sub-pleural haemorrhages shown in the Image are seen in", "options": [{"label": "A", "text": "Hanging", "correct": false}, {"label": "B", "text": "Drowning", "correct": true}, {"label": "C", "text": "Strangulation", "correct": false}, {"label": "D", "text": "Thermal injury", "correct": false}], "correct_answer": "B. Drowning", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892462318-QTDF027003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Drowning The alveolar walls may rupture due to increased pressure during forced expirations, and produce haemorrhages, which when present subpleural are called \"Paltauf's haemorrhages\"in a case of drowning. Paltaufs haemorrhages are shining, pale pink or bluish-red, and may be minute or 3 to 5 cm. in diameter. They are usually present in about 50% of cases in the lower lobes of the lungs but may be seen on the anterior surfaces of the lungs, and the interlobar surfaces. Red and grey patches may be seen on the surface, due to Paltaufs haemorrhages and patchy interstitial emphysema respectively.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D: Pleural Haemorrhages occur when alveolar walls rupture which doesn't occur in hanging, strangulation and thermal injury.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A case of drowning was brought for autopsy. The samples of the lungs were submitted for histopathology. Emphysema Aquosum will be seen in drowning in", "options": [{"label": "A", "text": "Swimming pool with laryngospasm", "correct": false}, {"label": "B", "text": "Seawater", "correct": true}, {"label": "C", "text": "Immersion syndrome", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "B. Seawater", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Seawater Drowning fluid actually penetrates alveolar walls to enter the tissues and the blood vessels. This has been described as emphysema aquosum. It is present in about 80% of cases and is presumptive evidence of death from seawater</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . In case of Laryngospasm, water doesn't enter the lungs. Hence emphysema aquosum is not seen. Option: C. Immersion syndrome (hydrocution or submersion inhibition): Death results from cardiac arrest due to vagal inhibition. Hence no water enters the lungs in this case too. So emphysema aquosum is not seen.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "At autopsy on an infant, it is important to diagnose whether he has respired and whether there is air in the lungs. The following test compares the weight of the body to the lungs:", "options": [{"label": "A", "text": "Wredin’s test", "correct": false}, {"label": "B", "text": "Fodere's test", "correct": false}, {"label": "C", "text": "Ploucquet’s test", "correct": true}, {"label": "D", "text": "Raygat’s test", "correct": false}], "correct_answer": "C. Ploucquet’s test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ploucquet’s test The blood flow in the lung beds is so increased after breathing that their weight I almost doubled from 1/70 of the body weight before respiration to 1135 after respiration. The increase in weight is not constant and is not a reliable indication of breathing.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Wredin’s Test- Before birth, the middle ear contains gelatinous embryonic connective tissue but no air. With respiration, the sphincter at the pharyngeal end of eustachian tube relaxes and air replaces the gelatinous substances in few hours to five weeks. The middle ear must be opened underwater by removing tegmen tympani. A bubble of air comes out if the test is positive. Option: B. Fodere’s Test or Static Test: Lungs are ligated across their hila and separated. The average weight of both lungs before respiration varies from 30 to 40 g., and after respiration from 60 to 66 g. The increase in weight is due to the increased flow of blood. Option: D. Raygat’s Test- It is based on the fact that the volume of lung is increased on breathing which more than compensates the weight of the additional blood due to which their specific gravity is diminished. The specific gravity of lungs before respiration varies from 1040 to 1050 and about 940 after breathing.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which type of drowning is associated with hyperkalemia?", "options": [{"label": "A", "text": "Freshwater drowning", "correct": true}, {"label": "B", "text": "Seawater drowning", "correct": false}, {"label": "C", "text": "Dry drowning", "correct": false}, {"label": "D", "text": "Shallow water drowning", "correct": false}], "correct_answer": "A. Freshwater drowning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Freshwater drowning In the case of freshwater drowning, hyperkalemia may directly damage the myocardium, decreasing cardiac output reduced. The serum potassium increases (a powerful myocardial toxin). This increased load causes rapid overburdening of the heart and produces pulmonary oedema.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Seawater drowning - The exact opposite mechanism to that of freshwater drowning happens in this case. Hence no hyperkalemia is observed. Option: C. Dry drowning is a phenomenon where the person who falls into the water dies due to laryngospasm. Water doesn't enter the lungs Option: D. Shallow water drowning- This happens in the case of infants, children and adults with comorbidities like epilepsy.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In freshwater drowning death occurs within 5 minutes of submersion due to ventricular fibrillation. The following reason is responsible for this:", "options": [{"label": "A", "text": "Total asphyxia is produced due to freshwater", "correct": false}, {"label": "B", "text": "Laryngospasm causing vagal inhibition", "correct": false}, {"label": "C", "text": "Hemoconcentration of blood caused by osmotic pressure effect", "correct": false}, {"label": "D", "text": "Hemodilution, overloading of the heart and hemolysis leading to the release of potassium", "correct": true}], "correct_answer": "D. Hemodilution, overloading of the heart and hemolysis leading to the release of potassium", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hemodilution, overloading of the heart and hemolysis leading to the release of potassium In the case of freshwater drowning, cardiac arrhythmias leading to ventricular tachycardia and fibrillation occur, probably due to hypoxia and hemodilution. Hypoxaemia and hyperkalemia may directly damage the myocardium, decreasing cardiac output reduced. The serum potassium increases (a powerful myocardial toxin). This increased load causes rapid overburdening of the heart and produces pulmonary oedema.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. In case of freshwater drowning, ventricular fibrillation is due to hypoxia and hemodilution and not total asphyxia. Option: B. laryngospasm causing vagal inhibition is seen in dry drowning and not in freshwater drowning. Option: C. Hemodilution occurs in freshwater drowning and not hemoconcentration. It is seen in seawater drowning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Gettler test is based on study ………. level of blood in heart chambers:", "options": [{"label": "A", "text": "Calcium", "correct": false}, {"label": "B", "text": "Chloride", "correct": true}, {"label": "C", "text": "Potassium", "correct": false}, {"label": "D", "text": "Sodium", "correct": false}], "correct_answer": "B. Chloride", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Chloride GETTLER TEST: Normally, the chloride content is almost equal in the right and left chambers of the heart and is about 600mg. per 100 ml. When drowning occurs in freshwater, water tends to pass from the lungs to the blood and the blood gets diluted by as much as 72% in 3 minutes, and the blood in the left side of the heart will show chloride content up to 50% lower than usual. In drowning in seawater, water is absorbed from the pulmonary circulation into the alveolar spaces which may be up to 42% and due to the hemoconcentration, the chloride content in the left side of the heart shows an increase of up to 30 to 40%. A 25% difference in chloride is significant.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A, C & D. Calcium, Potassium and Sodium are not reliable Indicators to differentiate freshwater and seawater drowning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body was recovered from a river bank. However, the police were not sure whether the death occurred due to drowning. One of the following is a sure sign of death due to drowning:", "options": [{"label": "A", "text": "Cutis anserine", "correct": false}, {"label": "B", "text": "Water in the stomach", "correct": false}, {"label": "C", "text": "Pulmonary oedema", "correct": false}, {"label": "D", "text": "same Diatoms detected in the bone marrow and drowning water", "correct": true}], "correct_answer": "D. same Diatoms detected in the bone marrow and drowning water", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>same Diatoms detected in the bone marrow and drowning water The finding of diatoms in the drowning fluid and the body tissues is in favour of drowning.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B & C. Cutis Anserina, water in the stomach and pulmonary oedema though are findings in drowning, are not sure signs of death due to drowning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The best tissue sample for diatom’s test:", "options": [{"label": "A", "text": "Lung", "correct": false}, {"label": "B", "text": "Liver", "correct": false}, {"label": "C", "text": "Brain", "correct": false}, {"label": "D", "text": "Bone marrow", "correct": true}], "correct_answer": "D. Bone marrow", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Bone marrow The drowning fluid and the particles in it, e.g., diatoms and planktons, pass from the ruptured alveolar wall into lymph channels and pulmonary veins and thus enter the left heart. Only a live body with circulation could transport diatoms from the lungs to the brain, bone marrow, liver and other viscera, and skeletal muscle. They are also found in the bile and urine. The bone marrow is highly suitable and reliable. The bone marrow of long bones, such as the femur, tibia and humerus or sternum is examined for diatoms.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C. Lung, liver and brain though are body tissues where diatoms can be found in a case of death due to drowning, bone marrow is the best tissue sample in the body.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A boy jumped into the pool on a winter morning. He suddenly collapsed and sank to the bottom of the pool. The cause of death in Immersion Syndrome is:", "options": [{"label": "A", "text": "Severe electrolyte imbalances", "correct": false}, {"label": "B", "text": "Asphyxia", "correct": false}, {"label": "C", "text": "Reflex cardiac inhibition", "correct": true}, {"label": "D", "text": "Coma", "correct": false}], "correct_answer": "C. Reflex cardiac inhibition", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Reflex cardiac inhibition Immersion syndrome (hydrocution or submersion inhibition): Death results from cardiac arrest due to vagal inhibition as a result of Cold water stimulates the nerve endings on the surface of the body, Water striking the epigastrium, Cold water entering ear drums, nasal passages, and the pharynx and larynx which cause stimulation of nerve endings of the mucosa.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Severe electrolytic imbalance occurs in case of wet drowning and not immersion syndrome. Option: B. Immersion syndrome occurs due to vagal inhibition and not asphyxia. Option: D. Immersion syndrome doesn't occur in a coma rather due to vagal inhibition.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 28-year-old male was travelling to the Maldives but was arrested at the Chennai Airport by the police after he became unconscious there and started to have generalised tremors. His blood and urine examination showed the presence of Cocaine, but on taking history he denied taking any drugs. His X-ray is given below in the image. This is a case of -", "options": [{"label": "A", "text": "Body packing", "correct": true}, {"label": "B", "text": "Body stuffer", "correct": false}, {"label": "C", "text": "Body pushers", "correct": false}, {"label": "D", "text": "Cocaine bugs", "correct": false}], "correct_answer": "A. Body packing", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893849328-QTDF070001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Body packing Body packing - A method of transporting or trafficking high quality narcotic drugs (heroin, cocaine). It is known as body- packing as the carrier swallows the drug cylinders and retrieve them after reaching the destination. CT is the best investigation to diagnose body packing. The given case scenario is indicating illegal drug smuggling known as Body packing. Illegal drugs, such as Cocaine, heroin, amphetamine and cannabis are compressed into cylinders of about 25 x 12 mm in size, heat-sealed in plastic film and wrapped again in multiple layers of latex (condoms, balloons, foil, fingers of rubber gloves, etc.) and swallowed. One packet may contain 3 to 7 g of the narcotic. Drugs such as loperamide or diphenoxylate hydrochloride with atropine may be taken to reduce gut motility and prevent the passage of the packages on a long-distance flight, before the end of the It is done for the purpose of smuggling, known as “Body packing”. They can conceal half a of the drug. On arrival at his destination, the courier takes a laxative, retrieves the packets and passes them on to the “pusher” who distributes the drug. The packets may cause bowel obstruction secondary to torsion, intussusception or impaction. Many times the packets become unsealed or burst in the small intestine, especially cocaine-filled containers, allowing massive absorption and causing the courier's death from poisoning. Even if the packets do not rupture, drugs may passively diffuse from the stomach into surrounding organs, including the lower lobe of the left lung, left lobe of the liver and heart and appear in the circulation and urine. People who swallow these are known as ‘Mules’. X-ray of body packers showing drugs in cylinders which may cause intestinal obstruction and/or severe intoxication due to rupture.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B. Body stuffer - These are people who when arrested swallow illegal drugs for concealing evidence from authorities. They are known as drug peddlers. They have small packets of drug in their pockets to distribute to different people. Option C. Body pushers - They are people who conceal, who hide small packets in natural orifices of the body like ears, nose, throat, vagina, rectum. Option D. Cocaine bugs - In Cocaine abuse Cocaine bugs or Magnan's Symptoms are seen in which there is a feeling as if grains of sand are lying under skin. It is also felt as if some small insects are creeping on the skin giving rise to itching sensation. It is a type of Tactile Hallucination also known as Formication.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 25-year-old male was brought to the ER after he deliberately inhaled a substance in order to abuse it for its psychotropic and hallucinogenic properties. It was later identified as a case of chronic Drug abuse of volatile substances. There are various methods of this type of drug abuse, match the correct options from the given below for volatile solvent abuse examples:- Huffing - Volatile substance is poured on a handkerchief, gauze piece, or paper and from it, it is inhaled. Bagging - Volatile substance is inhaled and exhaled into a bag. Sniffing - The substance is used as a nasal spray. Douching -Substance is directly inhaled from the mouth of the container. Mainlining - Intravenous administration of drugs mainly narcotics. Skin popping - The substance is used as an aerosol spray. Select the correct answer from given below code:", "options": [{"label": "A", "text": "1,2,3,4,5,6", "correct": false}, {"label": "B", "text": "2,3,5,6", "correct": false}, {"label": "C", "text": "1,2,3", "correct": false}, {"label": "D", "text": "1,2,5", "correct": true}], "correct_answer": "D. 1,2,5", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,2,5 Volatile substance abuse (solvent abuse, glue sniffing) involves the deliberate inhaling of a variety of substances, such as toluene, gasoline(petrol), xylene, benzene, chloroform, methylene and ethylene chloride, fluorocarbons, carbon tetrachloride, butane, propane, kerosine, isopropane, amyl nitrite, acetone, trichloroethylene, etc. for their psychotropic and hallucinatory properties. Volatiles such as paint stripper typewriting erasure fluid, brush cleaner, household aerosols, fabric cleaner, gasoline and glue solvent are misused. Huffing refers to inhaling vapours from a cloth that is saturated with the volatile substance and held over or near the nose and mouth. Bagging refers to inhaling and exhaling into a bag that has been filled with a small amount of a volatile substance. Clinical manifestations depend on the substance abused, Gaseous substance may be introduced directly into the mouth or nose from either a large cylinder or from the small ampoule cylinders. Others are used directly from pressurised aerosol cans, including pain-relieving Sniffing is done with jerry cans and petro- fillers. The sufferer often behaves totally irrationally, commits antisocial acts and may injure or even kill himself. Later the abuser will often have complete amnesia for the period of intoxication. Most of the abusers are young, usually male teenagers, and no physical withdrawal is Douching is a substance used as a nasal spray. Mainlining refers to the intravenous administration of drugs mainly narcotics. People who do this are called “Mainliners”. When frequently done with some needles, the results of needle tract ulcers are called Mainlining Scars. Skin popping is the subcutaneous injection of narcotics. Scars due to frequent subcutaneous injections of narcotics are known as Map shaped ulcers. So, skin popping is not used for aerosols. A correct explanation for Huffing, Bagging and mainlining is given.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Sniffing is the direct inhalation of a substance from the mouth of the container, Douching is the usage of the substance as a nasal spray and skin popping is the subcutaneous injection of narcotics. Scars due to frequent subcutaneous injections of narcotics known as Map shaped ulcers are wrongly matched. Option: B. Sniffing is the direct inhalation of substance from the mouth of the container and the skin popping explanation is wrongly matched. Option: C. The sniffing explanation is wrongly matched with the option.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Police busted a Rave party where teenagers were arrested with drug samples. A 27 years old male was caught who presented with symptoms like euphoria, heightened sensual awareness and increased psychic and emotional energy along with nausea, teeth grinding, blurred vision, anxiety, panic attacks and psychosis. With which of the following drug abuse case was it involved?", "options": [{"label": "A", "text": "LSD", "correct": false}, {"label": "B", "text": "MDMA", "correct": true}, {"label": "C", "text": "Cocaine", "correct": false}, {"label": "D", "text": "Nicotine", "correct": false}], "correct_answer": "B. MDMA", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>MDMA The given case scenario indicates MDMA drug abuse. MDMA(Methylenedioxymethamphetamine) also known as Molly / Ecstasy is similar to mescaline and is also known as one of the ‘club drugs’ or ‘rave drugs’ Because MDMA is used for euphoric stimulation in clubs or parties. The most commonly used hallucinogenic drugs are LSD and MDMA. It is supposed to interact with serotonergic neurons in the CNS. Acute symptoms include euphoria, heightened sensual awareness, and increased psychic and emotional energy. MDMA produces less amount of emotional liability, depersonalization and disturbance of thought. Adverse effects include nausea, teeth grinding, blurred vision, anxiety, panic attacks and psychosis. MDMA has been associated with sudden death due to cardiac arrhythmia. No specific treatment for acute overdose, only symptomatic treatment is given.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. LSD (Lysergic Acid Diethylamide) is obtained from rye fungus and is rapidly absorbed from GIT with an onset of action in 30-40 minutes. It affects levels of 5-HT levels in the brain. A common pattern of LSD use is Trip. Anxiolytics along with symptomatic treatment are Acute intoxication produces altered changes in vision and hearing, like floating feelings, illusions, and sensations of synesthesia, i.e., ‘seeing’ smells and ‘hearing colours. Option: C. Cocaine use produces a mild physical, but strong psychic dependence. A triphasic withdrawal syndrome follows an abrupt discontinuation of chronic cocaine use. In the crash phase (9 hrs to 4 days) there is anorexia, depression, agitation, excessive craving, hypersomnia, fatigue and exhaustion which is followed by normal mood, anxiety and anhedonia (next 4-7 days). In the third phase (extinction phase), there are no withdrawal symptoms but increased vulnerability to relapse. Bromocriptine and amantadine are useful in reducing cocaine cravings. Gabapentin is being used in adult addicts. Option: D. Nicotine is the active ingredient in cigarettes which causes intoxication, dependence, tolerance and withdrawal syndrome. Each cigarette contains 10mg of nicotine and the cigarette delivers 1-3mg of nicotine. Nicotine affects cholinergic receptors at the nucleus accumbens. It also increases acetylcholine, serotonin and beta-endorphin</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 28-year-old college student was found dead at her apartment, the Police retrieved many drug samples, needles, cigarettes, and alcohol bottles from her. Her friends told her that she was an alcoholic and a chronic drug abuser and always tried new methods to get high. On proper history from her close friends it was revealed that she had a compulsion of taking drugs, she had increased the doses of the drugs she had used earlier, and many times she had experienced withdrawal symptoms. It is known as-", "options": [{"label": "A", "text": "Drug Addiction", "correct": true}, {"label": "B", "text": "Drug Habituation", "correct": false}, {"label": "C", "text": "Harmful use", "correct": false}, {"label": "D", "text": "Acute Intoxication", "correct": false}], "correct_answer": "A. Drug Addiction", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Drug Addiction Drug Addiction - In it compulsion is present to take the drug, the tendency to increase the dose of the drug is present, and physical as well as psychological dependence is present. Characteristic symptoms of withdrawal are present and it causes harm to both individual and the society. A drug is any substance, or product used to modify physiological systems or pathological states for the benefit of recipients (WHO). Drug addiction is defined as a chronic disorder characterised by compulsive use of drugs(cravings) resulting in physical, psychological and social harm, and continued use despite evidence of harm. Drug addiction can be because of physical or psychological dependence on Drug habituation is a condition resulting from the repeated consumption of a drug, in which there is a psychological or emotional dependency on the drug. Caffeine and nicotine are habit-forming Drug addiction and drug habituation S.No. Feature Drug addiction Drug habituation 1. Compulsion Present Desire, but no compulsion 2. Dependence Psychological and physical Psychological, but not physical 3. Dose Tendency to increase No tendency to increase 4. Withdrawal symptoms Characteristic symptoms None or mild 5. Harm Both-individual and society Individual only Harmful use is continued drug use despite awareness of harmful medical and/or social effects of the drug being used / or a pattern of physically hazardous use of the drug (e.g-driving in intoxication). The diagnosis requires that actual damage should have been caused to the mental or physical health of the abuser. Harmful use is not diagnosed if dependence syndrome is present. Acute intoxication is a transient condition, resulting in disturbance of the level of consciousness, cognition, perception, behaviour or other psycho-physiological functions and responses. This is usually associated with high blood levels of the psychoactive substance. The intensity of intoxication lessens with time, and effects gradually disappear in the absence of further use of the substance. Recovery is complete, except where tissue damage or some complication has risen.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B. Drug Habituation - In it, there is desire but no compulsion, no tendency to increase the dose of the drug. Some degree of psychological but not physical dependence. None or mild withdrawal symptoms, and harm if any is primarily to the Option C . Harmful Use - Harmful use is continued drug use despite awareness of harmful medical and/or social effects of the drug being used / or a pattern of physically hazardous use of the drug (e.g-driving in intoxication). Option D. Acute Intoxication - Refers to unwanted physiological or psychological effects that cause maladaptive behaviour. It must produce disturbances in the level of consciousness, cognition, perception, effect, or behaviour that are clinically significant.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 14 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A man was brought for autopsy by the police. He was recovered from a roadside pavement where he used to sleep. The skin type shown in the Illustration is characteristic of", "options": [{"label": "A", "text": "Drowning", "correct": false}, {"label": "B", "text": "Neck ligature", "correct": false}, {"label": "C", "text": "High Voltage electric burns", "correct": true}, {"label": "D", "text": "High-Temperature water burns", "correct": false}], "correct_answer": "C. High Voltage electric burns", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893556063-QTDF060001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>High Voltage electric burns High voltage burns may be very severe with the charring of the body. Multiple individual and confluent areas of third-degree burns are seen. 1000 volts will jump several mm, and 100 kilovolts about 35 cm. Very high voltage currents produce massive tissue destruction with loss of extremities and rupture of organs. When bone is involved, the periosteum may be elevated, superficial layers of the bone may be destroyed, or fracture may occur. Sometimes, multiple lesions are found in the region of flexures of a limb where the current has passed across the joints instead of passing around it. High-tension electrical currents may produce multiple, small, discrete, pitted burns due to arcing from the conductor to the body without direct contact. Multiple burnt or punched-out lesions are produced due to the arc dancing over the body surface over large areas, which present 'crocodile flash burns'. Flashover often produces 'arc eye'. High amperage has an explosive blast-like effect and may produce injuries resembling bullet, stab or incised wounds.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. Drowning, Neck Ligature or High-temperature water burns do not resemble the skin type shown in the Illustration above. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 20-year-old male was repairing the electrical wires near a water puddle just outside his home. While handling the wires, he lost his balance, fell into the puddle, and got an electric shock. He was saved and taken to the nearby hospital. The entry point of the current is given in the image below. Which of the following statement is incorrect wrt the given image?", "options": [{"label": "A", "text": "It is specific and diagnostic of contact with electricity", "correct": false}, {"label": "B", "text": "Endogenous thermal burn", "correct": false}, {"label": "C", "text": "Where the tip of the wire or rod is at the right angle to the skin, the mark will present as an oblique hole", "correct": true}, {"label": "D", "text": "Histological examination of the electric mark usually shows coagulation of the dermis, with separation of the epidermis in some areas,", "correct": false}], "correct_answer": "C. Where the tip of the wire or rod is at the right angle to the skin, the mark will present as an oblique hole", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893556453-QTDF060002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Where the tip of the wire or rod is at the right angle to the skin, the mark will present as an oblique hole Where the tip of the wire or rod is at the right angle to the skin, the mark may present as a circular hole and not oblique. Hence option C is incorrect. The given image depicts the joule burn. Joule burns are endogenous thermal burns due to the heat generated in the body from electricity. Hence option B is correct.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. It occurs when there is contact with electricity and is specific and diagnostic. Option: D. Histological examination of the electric mark usually shows coagulation of the dermis, with separation of the epidermis in some areas- is a correct statement.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You were given sets of pictures during the practical examination. They are given below. Choose the incorrect statement wrt to them.", "options": [{"label": "A", "text": "IMAGE A depicts burns due to an air gap between metal and skin.", "correct": true}, {"label": "B", "text": "IMAGE B depicts high-tension electric currents.", "correct": false}, {"label": "C", "text": "IMAGE C depicts the path the lightning current takes in the body.", "correct": false}, {"label": "D", "text": "IMAGE A represents an endogenous type of burn.", "correct": false}], "correct_answer": "A. IMAGE A depicts burns due to an air gap between metal and skin.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893556473-QTDF060003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>IMAGE A depicts burns due to an air gap between metal and skin. IMAGE A depicts burns due to the air gap between metal and skin- this statement is wrong.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: D. Image A depicts a joule burn, which occurs at the point of contact with an electric It is an endogenous type of burn. The statement given in option A describes a flash/spark burn, whereas the image depicts a joule Hence it is an incorrect statement. Option: B. Image B depicts a crocodile burn due to high voltage or high-intensity Multiple burnt or punched-out lesions are produced due to the arc dancing over the body surface. Option: C. Image C depicts Lichtenberg’s flowers or filigree burns which occur in case of lightning. It depicts the path of the electric current in the body caused by the staining of the tissues from the haemoglobin from the lysed RBC.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 28-year-old female was doing cleaning work near the roadside when she came in contact with the electric wire near the pole, got electrocuted, and died on the spot. Which of the following current path will lead to death in this patient if it occurs due to ventricular fibrillation?", "options": [{"label": "A", "text": "ACD", "correct": false}, {"label": "B", "text": "AB", "correct": false}, {"label": "C", "text": "CD", "correct": false}, {"label": "D", "text": "AC", "correct": true}], "correct_answer": "D. AC", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893556567-QTDF060004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>AC In the given question, the path of the current which will lead to ventricular arrhythmia is given in image A- hand to hand Image D depicts the hand to the head. The heart is not involved in this. Image B depict- hand and arm contact, and the path of the current is very small. Image C- hand to feet. Hence, it is the most appropriate answer to this question.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Due to thunderstorms and heavy rainfall, the electricity of the whole society was cut down until the weather settled down. After that, u have to call an electrician as your apartment's lights are still not turned on. The electrician got an electric shock while handling sand and checking up for the defect. What will be your responsibility?", "options": [{"label": "A", "text": "Remain distant and inform emergency services and wait until they rescue him.", "correct": false}, {"label": "B", "text": "Pulled the person with bare hands.", "correct": false}, {"label": "C", "text": "Current should not be switched off.", "correct": false}, {"label": "D", "text": "Help him with the help of a wooden stick or by wrapping the hand in a dry cloth or newspaper.", "correct": true}], "correct_answer": "D. Help him with the help of a wooden stick or by wrapping the hand in a dry cloth or newspaper.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Help him with the help of a wooden stick or by wrapping the hand in a dry cloth or newspaper. Whenever a person gets an electric shock and is in contact with the source of electricity, he should not be pulled with bare hands (option B is incorrect.) The current should be switched off. (Hence option C is incorrect.) The victim should be moved by a stick, or the hands should be wrapped in dry cloth or newspaper, or rubber gloves are worn.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . We should save the patient and wait for emergency services to provide further treatment. Hence it is a wrong statement.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 35-year-old man was brought dead to the hospital after being electrocuted. He was taken for an autopsy examination. Which of the following internal features is not consistent with electrocution?", "options": [{"label": "A", "text": "Petechial haemorrhages may be found along the line of the current passage, under the endocardium, pericardium, pleura, brain and spinal cord.", "correct": false}, {"label": "B", "text": "Skeletal muscle in the path of the current may show Zenker's degeneration.", "correct": false}, {"label": "C", "text": "A foetus may survive the electrocuted mother, or a surviving mother may abort after electric injury.", "correct": false}, {"label": "D", "text": "Wax drippings or bone pearls are found in the subcutaneous tissue.", "correct": true}], "correct_answer": "D. Wax drippings or bone pearls are found in the subcutaneous tissue.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Wax drippings or bone pearls are found in the subcutaneous tissue. It is a wrong statement. The heat generated by the current may melt the calcium phosphate, which is seen radiologically as typical round density foci ('bone pearls' or \"wax drippings\"). Small balls of molten metal derived from the metal of the contacting electrode, so-called current pearls, may be carried deep into the tissues.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Petechial haemorrhages may be found along the line of the current passage, under the endocardium, pericardium, pleura, brain, and spinal cord is correct Option: B. Skeletal muscle in the path of the current may show Zenker's degeneration is found in electrocution. Option: C . A foetus may survive the electrocuted mother, or a surviving mother may abort after an electric injury is a correct statement.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "In case of a civil case, if the witness feels that the amount of fees paid to him is less", "options": [{"label": "A", "text": "He can inform the judge about it", "correct": true}, {"label": "B", "text": "He can write a letter to the lawyer stating his grievance", "correct": false}, {"label": "C", "text": "He can’t get any kind of increment in the fees since it’s a civil case", "correct": false}, {"label": "D", "text": "They get a fixed money of rupees 100 in order to meet the expenses", "correct": false}], "correct_answer": "A. He can inform the judge about it", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>He can inform the judge about it CONDUCT MONEY : It is the fee offered or paid to a witness in civil cases, at the time of serving the summons to meet the expenses for attending the Court. If the fee is not paid, or if he feels that the amount is less, the doctor can bring this fact to the notice of the Judge before giving evidence in the Court. The Judge will decide the amount to be paid. In criminal cases, no fee is paid to the witness at the time of serving the summons. He must attend the Court and give evidence because of the interest of the State in securing justice; otherwise, he will be charged with contempt of Court. However, in criminal cases, conveyance charges and daily allowance can be claimed by the doctor according to Government rules.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B : He has to inform the judge and not the lawyer about his grievance Option C : He may get an increment in the fees if his grievance is felt genuine by the judge Option D : The conduct money is not fixed. It may vary with each case according to the needs.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "According to Supreme Court, every hospital is required to issue a death certificate after the death in the hospital. All are true about the death certificate, except", "options": [{"label": "A", "text": "Is issued by a registered medical practitioner after thoroughly inspecting the body", "correct": false}, {"label": "B", "text": "Should be issued only after payment of fees", "correct": true}, {"label": "C", "text": "Should inform the police before issuing the death certificate if suspicious of foul play", "correct": false}, {"label": "D", "text": "Issuing or signing a false certificate is punishable under S. 197, I.P.C", "correct": false}], "correct_answer": "B. Should be issued only after payment of fees", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Should be issued only after payment of fees A medical practitioner is legally bound to give a death certificate, stating the cause of death without charging a fee, if a person whom he has been attending during his last illness dies (Registration of Births and Deaths Act, 1970)</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. A death certificate should not be issued by a doctor without inspecting the body and satisfying himself that person is really dead . Option: C. The certificate should not be delayed, even if the doctor's fees are not paid. The certificate should not be given if the doctor is not sure of the cause of death, or if there is the least suspicion of foul play . Option: D . In such cases, the matter should be reported to the police. Issuing or signing a false certificate is punishable under S. 197, I.P .C.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A stab victim was admitted to the emergency. He was about to die and wanted to talk about the incident. The doctor decided to record the dying declaration. The false statement about the dying declaration is", "options": [{"label": "A", "text": "A dying declaration is dealt with in Section 32 IPC", "correct": true}, {"label": "B", "text": "If there is time, the Executive magistrate should be called to record the declaration.", "correct": false}, {"label": "C", "text": "The statement can also be recorded by the village headman or police", "correct": false}, {"label": "D", "text": "Leading questions should not be put", "correct": false}], "correct_answer": "A. A dying declaration is dealt with in Section 32 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A dying declaration is dealt with in Section 32 IPC DYING DECLARATION: It is a written or oral statement of a person, who is dying as a result of some unlawful act, relating to the material facts of the cause of his death or bearing on the circumstances (S.32, I.E.A.).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. If there is time, the Executive magistrate should be called to record the declaration. Before recording the statement. The doctor should certify that the person is conscious and his mental faculties are normal (compos mentis). If the condition of the victim is serious, and there is no time to call a Magistrate, the doctor should take the declaration in the presence of two witnesses. Option: C. The statement can also be recorded by the village headman, police or any other person, but its evidential value will be less. While recording the dying declaration, the oath is not administered, because of the belief that the dying person tells the truth. Statement: The statement should be recorded in the man's own words, without any alteration of terms or phrases. Option: D. Leading questions should not be put. The declarant should be permitted to give his statement without any undue influence, outside prompting or assistance. If a point is not clear, a question may be asked to make it clear, but the actual question and the answer received should be recorded. It should then be read over to the declarant, and his signature or thumb impression is taken. The statement made must be of fact and not opinion. If the declaration is made in the form of an opinion or conclusion, questions should be asked by the recorder to bring out the facts that are the basis for the conclusion. While recording the statement, if the declarant becomes unconscious, the person recording it must record as much information as he has obtained and sign it. If the dying person is unable to speak but is able to make signs in answer to questions put to him, this can be recorded and it is considered as a \"verbal statement\". The doctor and the witness should also sign the declaration. If the statement is written by the declarant himself, it should be signed by him, the doctor and the witnesses.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Person A’s earlier statement regarding the facts on oath and subsequent statement on oath are opposite to each other, and they cannot be reconciled. Therefore person A can be punished under", "options": [{"label": "A", "text": "IPC 193", "correct": true}, {"label": "B", "text": "IPC 191", "correct": false}, {"label": "C", "text": "IPC 197", "correct": false}, {"label": "D", "text": "IPC 201", "correct": false}], "correct_answer": "A. IPC 193", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>IPC 193 The witness is liable to be prosecuted for perjury, and the imprisonment may extend to seven years (S. 193, I.P.C.).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. PERJURY: Perjury means giving wilful false/ fabricated evidence. Whoever, being legally bound by an oath, or by an express provision of law to state the truth, or being bound by law to make a declaration upon any subject, makes any statement which is false, and which he either knows or believes to be false or does not believe to be true, is said to give false evidence (S.l91 and 192, I.P.C. 344, Cr.P.C.). It occurs if the person's earlier statement regarding the facts on oath and subsequent statement on oath are opposed to each other, and cannot be reconciled. Option: C. 197 IPC:- Issuing or signing false certificate.-Whoever issues or signs any certificate required by law to be given or signed, or relating to any fact of which such certificate is by law admissible in evidence, knowing or believing that such certificate is false in any material point, shall be punished in the same manner as if he gave false evidence. Option: D . S 201 IPC:- Causing disappearance of evidence of the offence, or giving false information to screen offender.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "False statement about the examination in chief is", "options": [{"label": "A", "text": "It consists of questions put to him by the lawyer (counsel or advocate) for the side which has summoned him.", "correct": false}, {"label": "B", "text": "In this leading questions are allowed.", "correct": true}, {"label": "C", "text": "The doctor should help the prosecutor in framing proper questions in proper sequence so that all essential facts are elicited.", "correct": false}, {"label": "D", "text": "ln, a criminal trial, the burden to prove is always on the prosecution (adversarial system of trial).", "correct": false}], "correct_answer": "B. In this leading questions are allowed.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>In this leading questions are allowed. In this leading questions are not allowed, except in those cases, where the Judge is satisfied that a witness is hostile (S.I42 and 154, I.E.A.)</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Examination-in-chief (direct examination) (S.137, I.E.A.): This is the first examination of a witness. It consists of questions put to him by the lawyer (counsel or advocate) for the side which has summoned him. In criminal acts committed by an individual or group, the State becomes a party instead of the aggrieved person, and starts criminal prosecution, which is titled \"State versus A\". Option: C. If the witness intends to modify any of his findings or conclusions, these should be pointed out to the lawyer. The doctor should help the prosecutor in framing proper questions in proper sequence so that all essential facts are elicited. Option: D. In a criminal trial, the burden to prove is always on the prosecution (adversarial system of trial). and the accused is presumed to be innocent till the contrary is proved against him. In Government prosecution cases. the public prosecutor first examines the witness (S.24 and 25 Cr.P.C.). If a witness is called by a private party. He is first examined by the lawyer of that party. The object is to elicit all relevant, convincing medical facts (S.l38, I.E.A.). and the conclusions that the doctor has drawn from the facts. The doctor may have to interpret the findings of non-medical ancillary investigations provided by scientific laboratories, analysts and serologists, in all cases where the medical aspects are at issue. Before giving evidence, it is advisable that the doctor meets the public prosecutor, and discuss the previously prepared report, the certificate of death, photographs, etc., that the witness intends to show in the Court, and an outline or pattern should be worked out for the best way to elicit his testimony. The lawyer will be able to advise the doctor on the matters that he will attempt to emphasize and about the anticipated content of cross-examination.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Hair, a knife and a blood-stained handkerchief were collected from a crime scene place. All the specimens were then verified and later produced to the court. Which among the following term describes the method of verification of collected objects from the time until it's produced in the court?", "options": [{"label": "A", "text": "Chain of custody of specimens", "correct": false}, {"label": "B", "text": "Chain of custody of evidence", "correct": true}, {"label": "C", "text": "Chain of collection of specimens", "correct": false}, {"label": "D", "text": "Chain of collection of evidence", "correct": false}], "correct_answer": "B. Chain of custody of evidence", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Chain of custody of evidence Chain of Custody of Evidence: It is a method to verify the actual possession of an object from the time it was first identified until it is offered as evidence in Court. Each specimen when obtained should be labelled with the victim's name, the time and date, the nature of the specimen, and identification number, and signed by the doctor. This information must be documented each time the material is handled by another person, and that person must give a receipt for the material and be included in the chain of custody. The evidence must not be damaged. Contaminated, or altered in any significant way. The shorter the chain the better.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Since the above-mentioned is the chain of custody of evidence, other Options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Re-examination of a witness is conducted by:", "options": [{"label": "A", "text": "Public prosecutor", "correct": true}, {"label": "B", "text": "Defense lawyer", "correct": false}, {"label": "C", "text": "Judge", "correct": false}, {"label": "D", "text": "Police officer", "correct": false}], "correct_answer": "A. Public prosecutor", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Public prosecutor Re-examination (Re-direct examination):- This is conducted by the lawyer for the side which has called the witness. The object is to correct any mistake or to clarify or add details to the statements the witness has made in cross-examination. It is an opportunity for the witness to explain more fully some answer which might appear damaging to his direct evidence, because of skilful questioning or tactics by the cross-examiner. The witness should not bring in any new matter at this stage. The opposing lawyer has the right of re-cross-examination on the new point raised. Leading questions are not allowed.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C & D. Since Re-examination is conducted by the lawyer for the side which has called the witness, that is, Public Prosecutor. Hence the other three are not the correct options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "While giving evidence in court the Judge can ask questions at:", "options": [{"label": "A", "text": "Examination–in–chief", "correct": false}, {"label": "B", "text": "Cross-examination.", "correct": false}, {"label": "C", "text": "Re-examination", "correct": false}, {"label": "D", "text": "Any stage", "correct": true}], "correct_answer": "D. Any stage", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Any stage The Judge may ask any question, in any form, about any fact. Relevant or irrelevant, at any stage of the examination to clear up doubts. The Court is also empowered to recall and re-examine any witness already examined. If his evidence appears to the Court to be essential to the just decision of the Court</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C. The lawyers of the respective sides only have to wait for their turns in specific examinations. Unlike lawyers, the judge can ask any question at any time.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "After an explosion injury in a crowded market, multiple persons were admitted to the emergency. Triage was started and screening was started to know internal injury. The most common organ involved in blast injuries:", "options": [{"label": "A", "text": "Lung", "correct": true}, {"label": "B", "text": "Liver", "correct": false}, {"label": "C", "text": "Intestines", "correct": false}, {"label": "D", "text": "Brain", "correct": false}], "correct_answer": "A. Lung", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lung The explosion is defined as the sudden release of previously confined energy and is characterised by the production of heat, a large amount of gas & plenty of noise. Atomic explosions. Mechanical explosions- due to a build-up of pressure e.g. Steam in a steam boiler. Chemical explosions- Dispersed & Condensed. When an explosion occurs, explosive material is converted into a large volume of gas with the release of a tremendous amount of energy & pressures up to 1000 tons/sq inch (15,000 atm. pressure) & temperature up to 3000 °C. A person can be injured in many ways by an explosion:- Disruptive effects of blasts- due to the victim being in contact or immediate vicinity of the bomb, he may be blown to pieces. Flame & Radiant heat- temperature of explosive gases can reach up to 3000 °C and the radiated heat can cause \"flash burns\" (when the person is between a foot of the bomb). Air blast- An explosion produces a 'shock wave' which spreads concentrically from the site of an explosion at about the speed of sound. This wave of very high pressure is followed by a weak wave of negative pressure (below atmospheric pressure), a suction effect which lasts about 5 times as long. The shock wave lasts for milliseconds and has a pressure exceeding 100 pounds/sq. inch is necessary to cause serious damage to a body. A shock wave can knock a person down, more objects & demolish buildings (much like an earthquake). Lungs- \"blast lung\". Ear- T.M. Rupture + haemorrhage in the ear. GIT & Others- Sub-peritoneal haemorrhages, laceration of internal organs, intracranial haemorrhage, contusion of brain, aorta & heart, ruptured stomach & bowel. Death may occur from pulmonary air embolism. Underwater/Immersion blast- When an explosion occurs in the water, Solid blast- when the pressure wave forces a solid material against the body. In these GIT damage is more common than lung damage. Sometimes the death may occur without any external injury. Flying missiles- The bomb may drive multiple fragments of the bomb or pieces of nearby objects e.g. Gravel, glass, wood, brick, plaster etc. Through the air into the skin and cause bruises, abrasions and puncture lacerations (this triad of injuries is diagnostic) all over the skin. Falling masonry- When a building is destroyed by a bomb blast the persons inside may sustain multiple injuries caused by the collapsing masonry. The cause of death is usually traumatic asphyxia. Poisoning by fumes- If a bomb explodes in a confined or closed space, enough CO may be produced to cause death by asphyxia.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B & D Liver, brain and other solid organ involvement are not as common as hollow organs. Option intestine involvement is seen in underwater explosions.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was brought to the emergency in an unconscious state. Blood spectroscopy showed the presence of carboxyhemoglobin. More than 5% Carboxyhaemoglobin is seen in:", "options": [{"label": "A", "text": "Ante mortem burns", "correct": true}, {"label": "B", "text": "Cyanide poisoning", "correct": false}, {"label": "C", "text": "Drowning", "correct": false}, {"label": "D", "text": "Electrocution", "correct": false}], "correct_answer": "A. Ante mortem burns", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ante mortem burns The presence of carbon particles and an elevated level of CO saturation in the blood are absolute proof that the victim was alive when the fire occurred</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B, C & D: Cyanide poisoning, drowning and electrocution do not show the presence of carboxyhemoglobin.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "After a bomb explosion in a crowded market, several persons were brought in the emergency. Marshall’s triad in a blast is seen due to:", "options": [{"label": "A", "text": "Primary blast injuries", "correct": false}, {"label": "B", "text": "Secondary blast injuries", "correct": true}, {"label": "C", "text": "Tertiary blast injuries", "correct": false}, {"label": "D", "text": "Contributed by all.", "correct": false}], "correct_answer": "B. Secondary blast injuries", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Secondary blast injuries Marshall’s triad consists of the presence of punctuate lacerations, abrasions and bruises in a blast victim. They result from flying missiles generated by an explosion.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Primary blast injury-due to the pressure effects of blast wave (barotraumas) Option: C. Tertiary blast injuries- the victim was thrown by the blast wind or falling of mass on the victim. Option: D. Marshall’s triad injuries are not caused by the blast waves.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 13 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The ideal place to record temperature in a dead body is from:", "options": [{"label": "A", "text": "Axilla", "correct": false}, {"label": "B", "text": "Mouth", "correct": false}, {"label": "C", "text": "Rectum", "correct": true}, {"label": "D", "text": "Groin", "correct": false}], "correct_answer": "C. Rectum", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Rectum A laboratory thermometer 25 cm. long, with a range of 0 to 50°C. Which can be read in single degrees is used. The rectum is the ideal place to record temperature, except in cases of sodomy. The thermometer should be inserted 8 to 10 cm. and left there for two minutes. Variations in rectal temperature: The rectal temperature is between 36.5 to 37.5°C. Rectal temperature is about 0.6°C higher than oral. There are individual and daily variations up to 1 to 1.5°C. Being the lowest in the early morning and highest in the late evening. During sleep, the rectal temperature is half' to one°C lower.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option : A, B & D. Axilla, mouth and groin are not the ideal places to record temperature in a dead body. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 39 yrs aged man presents to the ER at 1 AM with complaints of severe chest pain for 5 hours. No h/o such complaints in the past. No known comorbidities. He became unresponsive as he was giving his history and succumbed to death. What is this kind of death known as?", "options": [{"label": "A", "text": "Sudden death", "correct": true}, {"label": "B", "text": "Cardiac arrest", "correct": false}, {"label": "C", "text": "Respiratory arrest", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "A. Sudden death", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sudden death SUDDEN DEATH:-Death is said to be sudden or unexpected when a person not known to have been suffering from any dangerous disease, injury or poisoning is found dead or dies within 24 hours after the onset of terminal illness</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C & D: Since the above incident typically presents a case of sudden death, other Options of cardiac and respiratory arrest are insignificant in this context. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An unknown dead body was identified by the police near a bus stand. His eyes appeared like the image shown below. What is the appearance of the eye called?", "options": [{"label": "A", "text": "Tache noir", "correct": true}, {"label": "B", "text": "Kevorkian sign", "correct": false}, {"label": "C", "text": "Tardieu spots", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "A. Tache noir", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893408982-QTDF055003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Tache noir TACHE NOIR:-film of cell debris and mucus forms two yellow triangles on the sclera at each side of the iris, with a base towards the margin of the cornea and apex towards medial or lateral canthus of the eye, which become brown and then black called \"tache noir\" within 3 to 4 hours, upon which dust settles, and the surface becomes wrinkled</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Fragmentation or segmentation (tuking or shunting) of the blood columns (Kevorkian sign) in the retinal vessels appear minutes after death and persists for about an hour. Option: C Petechial haemorrhages, known as Tardieu spots, are most marked where capillary congestion is most prominent for mechanical reasons. Their distribution lies above the level of obstruction. They appear commonly in the scalp, eyelids and face in hanging and strangulation and the zone above the compression level in traumatic asphyxia. A hand lens helps identify petechial haemorrhages.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The given appearance is caused due to", "options": [{"label": "A", "text": "Reduced Hemoglobin", "correct": false}, {"label": "B", "text": "Sulfhemoglobin", "correct": true}, {"label": "C", "text": "Methemoglobin", "correct": false}, {"label": "D", "text": "Hematin Crystals", "correct": false}], "correct_answer": "B. Sulfhemoglobin", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893409136-QTDF055004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sulfhemoglobin The Marbling of Skin: The superficial veins, especially over the roots of the limb, thighs, sides of the abdomen, shoulders, chest and neck, are stained greenish-brown or purplish-red depending on the total amount of sulphhaemoglobin formation within the affected vessels (linear branching pattern) due to the haemolysis of red cells, which stains the wall of the vessel and infiltrates into the tissue, giving a marbled appearance (red, then the greenish pattern in skin resembling the branches of a tree) This starts in 24 hours but is prominent in 36 to 48 hours. The clotted blood becomes fluid, so the position of the postmortem staining is altered, and the fluid blood collects in the serous cavities. Putrefactive effusion of foul -smelling blood stained fluid into the pleural cavities usually ~tarts at about the time when the skin becomes macerated; effusions usually do not exceed 60 to 100 ml. unless death resulted from drowning, when several hundred ml. of drowning medium which oozed out through the lungs and visceral pleura, may be present in the thoracic cavities. The reddish-green colour of the skin may become dark green or almost black in 3 to 4 days.</p>\n<p><strong>Random:</strong></p><p>Explanation For incorrect Options:- Option: A, C & D. Reduced Hemoglobin, methemoglobin, or hematin Crystals do not cause skin Marbling. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In the graphic representation of postmortem changes, an inverted ‘S” pattern of the graph is most commonly indicative of which postmortem change", "options": [{"label": "A", "text": "Rate of putrefaction in water", "correct": false}, {"label": "B", "text": "Rigor mortis", "correct": false}, {"label": "C", "text": "Algor mortis", "correct": true}, {"label": "D", "text": "Flaccidity of muscles", "correct": false}], "correct_answer": "C. Algor mortis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Algor mortis The cooling of the body ('chill of death') after death is a complex process which does not occur at the same rate throughout the body.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. Rate of putrefaction, Rigor mortis and Flaccidity of muscles do not show as curved graph. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A condition shown below is used in", "options": [{"label": "A", "text": "Estimation of time of death", "correct": true}, {"label": "B", "text": "Manner of death", "correct": false}, {"label": "C", "text": "Cause of death", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "A. Estimation of time of death", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893409261-QTDF055006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Estimation of time of death The condition shown is teche noir. Suppose the eyelids are open for a few hours after death. In that case, a film of cell debris and mucus forms two yellow triangles on the sclera at each side of the iris, with the base towards the margin of the cornea and the apex towards the medial or lateral canthus of the eye, which become brown and then black called \"tache noir\" within 3 to 4 hours, upon which dust settles, and the surface becomes wrinkled (artefact).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B, C & D . Tache Noir cannot estimate the manner of death and Cause of death. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Suppose the eyelids are open for a few hours after death. In that case, a film of cell debris and mucus forms two yellow triangles on the sclera at each side of the iris, with the base towards the margin of the cornea and the apex towards the medial or lateral canthus of the eye, which become brown and then black called \"tache noir.\" This occurs within the?", "options": [{"label": "A", "text": "1 2 hours of death", "correct": false}, {"label": "B", "text": "2 to 3 hours of death", "correct": false}, {"label": "C", "text": "3 to 4 hours of death", "correct": true}, {"label": "D", "text": "4 to 5 hours of death", "correct": false}], "correct_answer": "C. 3 to 4 hours of death", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>3 to 4 hours of death Suppose the eyelids are open for a few hours after death. In that case, a film of cell debris and mucus forms two yellow triangles on the sclera at each side of the iris, with the base towards the margin of the cornea and apex towards the medial or lateral canthus of the eye, which become brown and then black called \"tache noir\" within 3 to 4 hours, upon which dust settles, and the surface becomes wrinkled (artefact).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. Since tache noir occurs within 3 to 4 hours of death, other timeframes are irrelevant. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During life, the intraocular tension varies between 14 to 25 gm; soon after death, it is less than 12 gm; within half an hour, it is less than 3 gm and becomes nil at the end of?", "options": [{"label": "A", "text": "1 hour", "correct": false}, {"label": "B", "text": "1 hour 15 minutes", "correct": false}, {"label": "C", "text": "1 hour 45 minutes", "correct": false}, {"label": "D", "text": "2 hour", "correct": true}], "correct_answer": "D. 2 hour", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>2 hour CHANGES IN THE EYE: Flaccidity of the Eyeball after death: The eyes look sunken and become softer within minutes due to reduced intraocular tension. During life, the intraocular tension varies between 14 to 25 gm; soon after death, it is less than 12 gm; within half an hour, it is less than 3 gm., and becomes nil at the end two hours.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C. Since the intraocular tension becomes nil at the end of two hours, other timeframes in the other options are insignificant. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The earliest change in the eye after death is", "options": [{"label": "A", "text": "Tache noir", "correct": false}, {"label": "B", "text": "Kevorkian sign", "correct": true}, {"label": "C", "text": "Macular hole", "correct": false}, {"label": "D", "text": "Dropping of IOP to zero", "correct": false}], "correct_answer": "B. Kevorkian sign", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Kevorkian sign CHANGES IN THE EYE after death: Loss of Corneal Reflex: This is found in all cases of profound insensibility,g. epilepsy, narcotic poisoning, and general anaesthesia and therefore, not a reliable sign of death. The opacity of the Cornea: This may occur in certain diseases (cholera, wasting diseases) before death. The opacity is due to drying and is delayed for about two hours if the lids are closed after death. Suppose the eyelids are open for a few hours after death. In that case, a film of cell debris and mucus forms two yellow triangles on the sclera at each side of the iris, with the base towards the margin of the cornea and apex towards the medial or lateral canthus of the eye, which become brown and then black called \"tache noir\" within 3 to 4 hours, upon which dust settles, and the surface becomes wrinkled (artefact). Flaccidity of the Eyeball: The eyes look sunken and become softer within minutes due to reduced intraocular tension. During life, the intraocular tension varies between 14 to 25 gm; soon after death, it is less than 12 gm; within half an hour, it is less than 3 gm., and becomes nil at the end two hours. Pupils: Soon after death, pupils are slightly dilated because of the relaxation of muscles of the iris. Later, they are constricted with the onset of rigour mortis of the constrictor muscles and fluid evaporation. Retinal Vessels: Fragmentation or segmentation (tuking or shunting) of the blood columns (Kevorkian sign) in the retinal vessels appear within minutes after death and persists for about an hour. This occurs all over the body due to loss of blood pressure, but it can be seen only in the retina by an ophthalmoscope.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . Tache noir occurs in 4 hours, while Kevorkian sign happens within minutes. Option: B . A macular hole is a disease condition, not a postmortem finding. Hence not a correct answer. Option: C . IOP dropping to zero occurs in 2 hours while Kevorkian signs within minutes.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The following image is important for estimating the time since death. It is known as", "options": [{"label": "A", "text": "Tache noir", "correct": false}, {"label": "B", "text": "Kevorkian sign", "correct": true}, {"label": "C", "text": "Retina haemorrhage", "correct": false}, {"label": "D", "text": "Macular holes", "correct": false}], "correct_answer": "B. Kevorkian sign", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893409365-QTDF055010IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Kevorkian sign CHANGES IN THE EYE: Retinal Vessels after death: Fragmentation or segmentation (tuking or shunting) of the blood columns (Kevorkian sign) in the retinal vessels appear within minutes after death and persist for about an hour. This occurs all over the body due to loss of blood pressure, but it can be seen only in the retina by an ophthalmoscope.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . Tache noir does not help estimate the time of death. Hence it is not a correct answer. Option: C & D . Retinal haemorrhages and macular holes are not postmortem findings. Hence these Options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A thief tried to rob a house. However, the forensic expert could not trace the thief's fingerprint on any of the surfaces or objects in the house. What would be the probable disease that must have permanent fingerprint mutilation?", "options": [{"label": "A", "text": "Eczema", "correct": false}, {"label": "B", "text": "Leprosy", "correct": true}, {"label": "C", "text": "Rickets", "correct": false}, {"label": "D", "text": "Acanthosis nigricans", "correct": false}], "correct_answer": "B. Leprosy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Leprosy MUTILATION OF FINGERPRINTS: Criminals sometimes attempt to mutilate the pattern by self-inflicted wounds or burns, applying corrosives, or erosion against a hard surface. Still, they are not destroyed unless the actual skin is wholly destroyed. They produce additional characteristics. It leaves some parts of the skin undamaged unless skin grafts are made. In most cases of coeliac disease, there is moderate epidermal ridge atrophy and even pattern loss. Incomplete atrophy of the ridges is usually seen in dermatitis. Ridge alteration occurs in eczema, acanthosis nigricans, scleroderma, and dry or atrophic skin. Permanent impairment of the fingerprint pattern occurs in leprosy, electric injury, and after radiation exposure. In infantile paralysis, rickets, and acromegaly, though the pattern is not altered, the distance between the ridges can be changed. Fingerprints are better protected than other body parts, e.g., in case of burns, fingers are bent inwards against the palm.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Method of Identification using the imprint shown in the Illustration is known as :", "options": [{"label": "A", "text": "Dactylography", "correct": false}, {"label": "B", "text": "Podogram", "correct": false}, {"label": "C", "text": "Cheiloscopy", "correct": false}, {"label": "D", "text": "Poroscopy", "correct": true}], "correct_answer": "D. Poroscopy", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891816623-QTDF011002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Poroscopy This is a further study of fingerprints, described by Locard. The ridges on fingers and hands are studded with microscopic pores formed by mouths of ducts of subepidermal sweat glands. Each millimeter of a ridge contains 9 to 18 pores. These pores number in thousands per square centimeter. These pores are permanent and unchanged during life and vary in size, shape, width, starting and stopping on occasion and branching at points, position, extent and number, distribution and arrangement of the pores over a given ridge length in each individual. This method of examining pores is called poroscopy, and is useful when only fragments of fingerprints are available in which there is no specific pattern.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The forensic Team discovered a print at a crime scene. Method of identification using imprint shown in Image is:", "options": [{"label": "A", "text": "Dactylography", "correct": false}, {"label": "B", "text": "Podogram", "correct": false}, {"label": "C", "text": "Cheiloscopy", "correct": true}, {"label": "D", "text": "Poroscopy", "correct": false}], "correct_answer": "C. Cheiloscopy", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/questionImage-1687168986329-QTDF011004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cheiloscopy LIPPRINTS: (Cheiloscopy): The fissures and grooves on the lips are claimed to be characteristic of the individual. Lip prints are divided into six patterns specific to the individual; vertical, branched, intersected, reticular patterns, etc. 24 characteristic details have been identified. Identification is established if 7 to 9 characteristics tally. Minor differences between the right and the left and upper and lower lips can be noted. Lip prints are seen on crockery, cloth, paper, window panes, cigarette ends, etc.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A lady brought her daughter to a police station claiming one person to be her daughter’s father. Most informative test in parental identification:", "options": [{"label": "A", "text": "HLA", "correct": false}, {"label": "B", "text": "Parental likeness", "correct": false}, {"label": "C", "text": "Developmental defects", "correct": false}, {"label": "D", "text": "DNA fingerprinting", "correct": true}], "correct_answer": "D. DNA fingerprinting", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>DNA fingerprinting DNA fingerprinting is the most informative test in parental identification. DNA fingerprinting (DNA typing, DNA identification, or genetic typing) involves chemically dividing the DNA into fragments that form a unique pattern and then matching that \"identity profile\" with the pattern obtained from similarly testing a suspect's blood specimen. If the two patterns match, the possibility of error, i.e., the chance that they do not belong to the same individual, maybe less than one in 30 billion. Dr. Alec Jeffreys, in 1985, developed DNA fingerprinting.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Edmond Locard is most famous for?", "options": [{"label": "A", "text": "Fingerprint study", "correct": false}, {"label": "B", "text": "Theory of exchange", "correct": true}, {"label": "C", "text": "Stature estimation", "correct": false}, {"label": "D", "text": "Forensic ballistics", "correct": false}], "correct_answer": "B. Theory of exchange", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Theory of exchange Locard's Exchange Principle:- When any two objects come into contact, there is always a material transfer from each object to the other. Traces from the scene may be carried away on the person or tool of the criminal, and at the same time, traces from all or any of these may be left at the scene. Wherever a criminal goes, whatever he touches, and leaves will serve as silent evidence against him. e.g., fingerprints, footprints, hair, and fibers from clothes. Broken glass, tool marks, paints, scratches, blood or seminal stains, etc. It is evident, and its presence is proof of the crime.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Fingerprints are considered the best identification traits. However, these prints sometimes alter because of some diseases. Disease, which permanently alters fingerprint-", "options": [{"label": "A", "text": "Burns", "correct": false}, {"label": "B", "text": "TB", "correct": false}, {"label": "C", "text": "Psoriasis", "correct": false}, {"label": "D", "text": "Leprosy", "correct": true}], "correct_answer": "D. Leprosy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Leprosy Permanent impairment of fingerprints occurs in– Leprosy, electrocution & radiation exposure. Fingerprints were not altered, but the distance between ridges changed in Infantile paralysis, rickets & acromegaly. Fingerprint ridge alteration occurs in- eczema, acanthosis nigricans, scleroderma, dry or atrophic skin—ridge atrophy & loss of pattern in- Coeliac disease.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- OPTIONS: A, B & C . Burns, tuberculosis, and psoriasis do not change fingerprints.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "All are features of lead poisoning, EXCEPT:", "options": [{"label": "A", "text": "Diarrhea", "correct": true}, {"label": "B", "text": "Abdominal pain", "correct": false}, {"label": "C", "text": "Encephalopathy", "correct": false}, {"label": "D", "text": "Nephropathy", "correct": false}], "correct_answer": "A. Diarrhea", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Diarrhea Features of lead poisoning are:- Facial pallor Anemia Lead line Lead palsy Encephalopathy Cardiovascular System and Kidneys: Lead causes vascular constriction, leading to hypertension and permanent arteriolar degeneration. Chronic arteriosclerotic nephritis and interstitial nephritis occur. Reproductive System: Menstrual derangements, such as amenorrhoea, dysmenorrhoea, menorrhagia, sterility of both sexes and abortion are frequent. Abortion occurs in pregnant women between 3 to 6 months. Other Systems: They are dyspepsia, anorexia, emaciation, general weakness, exhaustion, irritability, foul breath, headache, vertigo, loss of hair, and drowsiness. Peripheral neuritis is rare.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Amyl nitrate is used as an antidote for which poisoning?", "options": [{"label": "A", "text": "Arsenic poisoning", "correct": false}, {"label": "B", "text": "Hydro cyanide poisoning", "correct": true}, {"label": "C", "text": "Lead poisoning", "correct": false}, {"label": "D", "text": "Phosphorus poisoning", "correct": false}], "correct_answer": "B. Hydro cyanide poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hydro cyanide poisoning Hydrocyanic poisoning treatment:- Break 0.2 ml. ampoule of amyl nitrite in a handkerchief and hold it over the patient's nose for 15 to 30 seconds every minute, until sodium nitrite infusion is started.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 12 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "After a thorough investigation, the police went to the accused house on the grounds of committing rape on a 4-year-old girl. The accused pretends to be having a mental disorder. He overreacts to whatever the police ask and frequently keeps changing facial expressions. However, the police suspect that the accused is completely normal but pretending to have a mental disorder. Which among the features differentiate real mental illness from feigned mental illness? Real mental illness", "options": [{"label": "A", "text": "Shows gradual onset", "correct": true}, {"label": "B", "text": "Is always present with a motive", "correct": false}, {"label": "C", "text": "Show resentment for fear of detection", "correct": false}, {"label": "D", "text": "Frequently changing facial expression", "correct": false}], "correct_answer": "A. Shows gradual onset", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Shows gradual onset SNO FEATURES TRUE INSANE FEIGNED INSANE Onset & Motive Usually gradual or rarely sudden but almost always without any motive Always sudden and there is some motive. Predisposing/exciting cause May be present, like h/o insanity in parents Not present Facial expression There are usually a peculiar characteristic facial expressions like worried look, agitated Normal or easily distinguishable Signs & Symptoms The true insane individual shows signs and symptoms of insanity irrespective of his conduct being observed or not A false insane will show signs of insanity only when he is observed and there is total absence of symptoms when he thinks that he is alone or not being watched Characteristic feature Sign and symptoms usually point to a particular type of insanity. (e.g. schizophrenia manis Rinolar disord A non insane person will do whatever comes in to his mind and his signs and symptoms don't indicate a particular type of insanity Mood Excited, depressed or fluctuating May over react to show abnormality in mood Habits Habits are invariably dirty or filthy. He may smear his body with stool or urine Habits are not usually dirty or filthy Physical manifestation Dry harsh skin, furred tongue, constipation, anorexia (loss of appetite) Not present Repeated examination Not worried about being repeatedly examined Shows dislike for repeated examinations. Insomnia Present Cannot persist, patient usually sleeps after a day or two Dressing up Carelessly dressed Dressed reasonably properly</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The Image shown is of a nut used to produce an artificial bruise. Which among the following is an ingredient of this nut", "options": [{"label": "A", "text": "Semicarpol", "correct": true}, {"label": "B", "text": "Croton", "correct": false}, {"label": "C", "text": "Abrin", "correct": false}, {"label": "D", "text": "Ricin", "correct": false}], "correct_answer": "A. Semicarpol", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891764341-QTDF009003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Semicarpol Artificial Bruises: When applied to the skin, some irritant substances produce injuries that simulate bruises. Juice of marking nut, Calotropis plumbago rose(the given picture shows marking nut). They are produced to make a false charge of assault.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Seminal stains on the clothes are important findings, and the resident examining a sexual assault victim is instructed for the same. Spermine in semen is detected by:", "options": [{"label": "A", "text": "Florence test", "correct": false}, {"label": "B", "text": "Barberio’s test", "correct": true}, {"label": "C", "text": "ELISA test", "correct": false}, {"label": "D", "text": "Agglutination-Inhibition test", "correct": false}], "correct_answer": "B. Barberio’s test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Barberio’s test A saturated aqueous or alcoholic solution of picric acid, when added to the spermatic fluid, produces yellow needle-shaped crystals of spermine picrate. In Barberio’s test, the presence of spermine from the prostate in semen is detected. More Specific tests for seminal fluid.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options: - Option: A. Florence’s test: Choline is detected in this method. A few drops of a liquid stain solution are extracted and taken on a slide. A reduction of Florence reagent (8%) W/V solution of Iodine in water containing 5% W/V of Potassium Iodide) is poured & allowed to mix slowly under a cover slip. Dark brown crystals of choline periodide, generally needle-shaped, formed within a few minutes. Option: C. ELISA test: The Sperm Antibody ELISA is a reliable and quantitative test for the determining antibodies directed against human spermatozoa. Option: D. Agglutination-inhibition test: provides a highly sensitive assay for small quantities of an antigen, g. pregnancy test, blood grouping.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A man was brought to the emergency with manic episodes. His friends said they were partying at a hotel where various illicit drugs were available. Is Rave a drug?", "options": [{"label": "A", "text": "Ecstasy", "correct": true}, {"label": "B", "text": "Cocaine", "correct": false}, {"label": "C", "text": "Heroin", "correct": false}, {"label": "D", "text": "Amphetamine", "correct": false}], "correct_answer": "A. Ecstasy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ecstasy Rave drugs are the drugs used in various dance parties and clubs. This is a brief list of some of the drugs by slang names and some of their effects: Ecstasy – Hallucinogen/Stimulant. Ecstasy is a synthetic drug similar to methamphetamine and the hallucinogen mescaline. Ecstasy can significantly increase heart rate and blood pressure and a sense of alertness. The stimulant effects, which enable users to dance for extended periods, may also lead to dehydration, hypertension, and heart or kidney failure. It is one of the most widely used drugs among club drugs. Ephedrine – Stimulant. Ephedrine is in the Amphetamine family and can cause heart attacks, seizures, agitation, palpitations, and other health problems. Ephedrine is a common weight-loss substance. Ketamine – Hallucinogen. Ketamine is usually snorted and is frequently used with other drugs like ecstasy, heroin and cocaine. The high lasts anywhere from 30 minutes to about 2 hours. Methcathinone – Stimulant. It produces an amphetamine-like The drug has a burst of energy and a feeling of invincibility, accompanied by well-being and euphoria. LSD – Hallucinogen. LSD induces abnormalities in sensory perceptions. Effects are unpredictable depending on the amount taken, the surroundings in which the drug is used, and the user’s personality, mood, and expectations. Results can include physical effects of dilated pupils, higher body temperature, increased heart rate and blood pressure, sweating, loss of appetite, sleeplessness, dry mouth, and tremors. Magic Mushrooms – Hallucinogen. The effects of Mushrooms are similar to LSD. They include illusions, hallucinations, and distorted perceptions of time and distance. Trips or episodes can consist of psychosis, convulsions, flashbacks, and possible death. Methamphetamine – Stimulant. Methamphetamine affects many areas of the central nervous system. Methamphetamine use has serious health consequences, including memory loss, aggression, violence, psychotic behaviour, and potential cardiac and neurological damage.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. cocaine: Cocaine is a stimulant drug. It can be snorted, injected, or smoked. Some other names for cocaine include coke; blow; powder; crack. Central nervous system (CNS) findings: Mydriasis, headache, bruxism, nausea, vomiting, vertigo, nonintentional tremor (g., twitching of small muscles, especially facial and finger), tics, explosive movements, and pseudohallucinations (e.g., cocaine bugs), Circulatory findings: Possible increase in blood pressure (BP), slowed or increased pulse rate (possibly with ventricular ectopy), and pallor, Respiratory findings: Increase in speed and depth, Temperature findings: Elevated body temperature, Behavioral results: Euphoria, elation, garrulous talk, agitation, apprehension, excitation, restlessness, verbalisation of impending doom, and emotional lability. Option: C. Heroine: Heroin is a highly addictive drug made from morphine. It can be injected, snorted, or smoked. Short-Term Effects: People who use heroin report feeling a \"rush\" (a surge of pleasure or euphoria). However, other common effects include dry mouth, a warm flushing of the skin, heavy feeling in the arms and legs, nausea and vomiting, severe itching, clouded mental functioning, going \"on the nod,\" a back-and-forth state of being conscious and semiconscious. Long-Term Effects: People who use heroin over the long term may develop: insomnia, collapsed veins for people who inject the drug, damaged tissue inside the nose for people who sniff or snort it, infection of the heart lining and valves, abscesses (swollen tissue filled with pus), constipation and stomach cramping, liver and kidney disease, lung complications, including pneumonia, mental disorders such as depression and antisocial personality disorder, sexual dysfunction for men, irregular menstrual cycles for women. Option: D. Amphetamine: Amphetamines are stimulant drugs. The effects are the same as of methamphetamine.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was charged with murder. He pleaded that a sudden and irresistible force compelled him to commit the offence. This is known as:", "options": [{"label": "A", "text": "Illusion", "correct": false}, {"label": "B", "text": "Obsession", "correct": false}, {"label": "C", "text": "Twilight state", "correct": false}, {"label": "D", "text": "Impulsiveness", "correct": true}], "correct_answer": "D. Impulsiveness", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Impulsiveness Impulse: This is a sudden and irresistible force compelling a person to the conscious performance of some action without motive or forethought. A sane person can control an impulse, but an insane person may do things on a whim. Types: Kleptomania- An irresistible desire to steal articles of little value. Pyromania- an irresistible desire to set things on fire. Mutilomania- An irresistible desire to mutilate animals. Dipsomania- an irresistible desire for alcoholic drinks at periodic intervals. Sexual impulses- including sexual perversions. Suicidal and homicidal impulses.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . Illusion misrepresents a “real” sensory stimulus. Option: B. Obsession is an idea or thought that continually preoccupies or intrudes on a person's mind. Option: C. Twilight state is seen in visual hallucinations, Epilepsy, Head injury, Hysteria, and Punch-drunkenness.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The mental health act was introduced to replace the lunacy act to give mentally ill person dignity. In the Mental Health Act, the term \"lunatic\" is replaced by:", "options": [{"label": "A", "text": "Mental patient", "correct": false}, {"label": "B", "text": "Mentally ill patient", "correct": true}, {"label": "C", "text": "Mentally disordered patient", "correct": false}, {"label": "D", "text": "Mentally unsound patient", "correct": false}], "correct_answer": "B. Mentally ill patient", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mentally ill patient Indian lunacy act was passed in 1972; it was replaced by the mental health act 1987, An Act to consolidate and amend the law relating to the treatment and care of mentally ill persons. It defines a “mentally ill person” as someone who needs treatment for any mental disorder other than mental retardation. The Mental Health Care Act 2017 was passed on 7 April 2017 and came into force on 29 May 2018. The act effectively decriminalised attempted suicide which was punishable under Section 309 of the Indian Penal Code.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was attended by a psychiatry resident who believed that he was dead already. A nihilistic attitude is characteristically seen with:", "options": [{"label": "A", "text": "Major depression", "correct": true}, {"label": "B", "text": "Manic psychosis", "correct": false}, {"label": "C", "text": "Schizophrenia", "correct": false}, {"label": "D", "text": "Pyromania", "correct": false}], "correct_answer": "A. Major depression", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Major depression Nihilistic- the person declares that he does not exist or that the world does not exist; seen in major depression.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options :- Option: B & C. Nihilistic delusion is not usually seen in psychosis or schizophrenia. Option: D . Pyromania is a type of impulse control disorder characterised by inability to resist starting fires.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The accused's lawyer submitted in court that the medical board had diagnosed his client with delusion. A delusion is a disorder of:", "options": [{"label": "A", "text": "Thought", "correct": true}, {"label": "B", "text": "Orientation", "correct": false}, {"label": "C", "text": "Perception", "correct": false}, {"label": "D", "text": "Reasoning", "correct": false}], "correct_answer": "A. Thought", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Thought Delusion is a false belief in something that is not a fact and persists even after its falsity has been demonstrated.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Delirium is the disorder of orientation. Option: C. Hallucination is the disorder of perception Option: D. The defect of reason must be that the defendant did not know what he was doing, or if he did know, he did not know the act was wrong.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The wife finds it difficult to manage her mentally ill husband at home. He keeps beating up whoever visits their home, steals money from the house, buys all the unwanted stuff, and abuses the wife with uncultured words. So she fulfils all the formalities laid by the government and admits him to a psychiatric hospital. The wife visits her husband every 15 days, and the husband stays there for 90 days. Even after staying in a psychiatric hospital for 90 days, the wife sees no improvement in her husband and feels that he would still be unmanageable if taken back home. She writes a reception again. Who would consider the allegations in the petition filed by the wife?", "options": [{"label": "A", "text": "Magistrate", "correct": true}, {"label": "B", "text": "Head of Psychiatry department", "correct": false}, {"label": "C", "text": "Doctor treating the husband", "correct": false}, {"label": "D", "text": "District health officer", "correct": false}], "correct_answer": "A. Magistrate", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Magistrate On receipt of an application for reception-, the Magistrate must consider the allegations in the petition and the evidence of mental illness as disclosed by the medical certificates. Reception Order on Application : The officer-in-charge of a psychiatric hospital can make an application to the Magistrate in case of a mentally ill person who is undergoing treatment under a temporary treatment order if he has satisfied that The treatment is required to be continued for more than six months, or It is necessary for the interest of the health and personal safety of the mentally ill person or the protection of others. The husband or wife of the mentally ill person, or any other relative, can apply in the prescribed form to the Magistrate. Upon receipt of the application, the Magistrate must consider the allegations in the petition and the evidence of mental illness disclosed by the medical certificates. He can personally examine the alleged mentally ill person. If satisfied, he may pass a Reception Order immediately or fix a date for consideration of the petition. Suppose the Magistrate is satisfied that it is necessary to detain the alleged mentally ill person in a psychiatric hospital. In that case, he passes a Reception Order (order for admission and detention) valid for 30 days. If he is unsatisfied, he may refuse the application, giving his reasons in writing, a copy of which is supplied to the applicant. A certified copy of the Reception Order is sent to the officer in charge of the psychiatric hospital.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A man went to court to get his marriage with his wife to be declared null and void as his wife was mentally ill. In which of the following can a marriage be declared null and void?", "options": [{"label": "A", "text": "If the partner's mental illness developed six months after marriage", "correct": false}, {"label": "B", "text": "If the partner's mental illness was present before the time of marriage", "correct": false}, {"label": "C", "text": "If the partner's mental illness was present at the time of marriage", "correct": true}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "C. If the partner's mental illness was present at the time of marriage", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>If the partner's mental illness was present at the time of marriage A marriage is considered invalid if, at the time of marriage, either party Is incapable of giving valid consent due to mental illness, or Though capable of giving valid license, has been suffering from such a kind or degree of mental disorder as to be unfit for marriage and procreation, or Has been suffering from recurrent attacks of unsoundness of mind or epilepsy.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "X and Y are friends. Y has a grudge against Z . So Y intoxicates X by mixing alcohol with another liquid and forcing persuades him to kill Z. As a result, Z is killed due to the act of X. A case is registered, and X is arrested as the accused. X can plead to the court that murdering Z was not his intention with no prior knowledge, and the act was committed because of Y according to:", "options": [{"label": "A", "text": "Sec 85 IPC", "correct": true}, {"label": "B", "text": "Sec 86 IPC", "correct": false}, {"label": "C", "text": "Sec 87 IPC", "correct": false}, {"label": "D", "text": "Sec 88 IPC", "correct": false}], "correct_answer": "A. Sec 85 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec 85 IPC Sec 85 IPC. Act of a person incapable of judgment because of intoxication caused against his will.-Nothing is an offence which is done by a person who, at the time of doing it, is, because of intoxication, incapable of knowing the nature of the act, or that he is doing what is either wrong or contrary to law; provided that the thing which intoxicated him was administered to him without his knowledge or against his will.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Sec 86 IPC. An offence requiring a particular intent or knowledge committed by one who is intoxicated.-In cases where an act done is not an offence unless done with specific knowledge or purpose, a person who does the show in a state of intoxication shall be liable to be dealt with as if he had the same knowledge as he would have had if he had not been intoxicated unless the thing which intoxicated him was administered to him without his knowledge or against his will. Option: C. Sec 87IPC Act not intended and not known to be likely to cause death or grievous hurt, done by consent.-Nothing which is not intended to cause death or unfortunate injury, and which is not known by the doer to be likely to cause death or grievous hurt, is an offence because of any harm which it may cause, or be intended by the doer to provoke, to any person, above eighteen years of age, who has given consent, whether express or implied, to suffer that harm; or because of any injury which it may be known by the doer to be likely to cause to any such person who has consented to take the risk of that harm. Option: D. Sec 88 IPC. Act not intended to cause death, done by consent in good faith for a person's benefit.-Nothing, which is not intended to cause death, is an offence because of any harm which it may cause or be planned by the doer to drive or be known by the doer to be likely to cause, to any person for whose benefit it is done in good faith, and who has given a consent, whether express or implied, to suffer that harm, or to take the risk of that harm. Illustration A, a surgeon, knowing that a particular operation is likely to cause the death of Z, who suffers from a painful complaint, but not intending to cause Z's death and intending in good faith, Z's benefit performs that operation on Z, with Z's consent. A has committed no offence.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Mc Naughten’s Rule is accepted in India and included in section ……….IPC:", "options": [{"label": "A", "text": "81", "correct": false}, {"label": "B", "text": "84", "correct": true}, {"label": "C", "text": "86", "correct": false}, {"label": "D", "text": "88", "correct": false}], "correct_answer": "B. 84", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>84 McNaughten’s Rule has also been accepted in India as the law of criminal responsibility and is included in Sec. 84, I.P.C. which is as follows: \"Nothing is an offence which is done by a person, who at the time of doing it, because of unsoundness of mind, is incapable of knowing the nature of the act, or that he is doing what is either wrong or contrary to law.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The law of criminal responsibility for an insane person in India is based upon the following:", "options": [{"label": "A", "text": "Mc Naught en's Rule", "correct": true}, {"label": "B", "text": "Durham’s Rule", "correct": false}, {"label": "C", "text": "Curren’s Rule", "correct": false}, {"label": "D", "text": "American Law Institute test", "correct": false}], "correct_answer": "A. Mc Naught en's Rule", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mc Naught en's Rule McNaughten’s Rule has also been accepted in India as the law of criminal responsibility and is included in Sec. 84, I.P.C. which is as follows: \"Nothing is an offence which is done by a person, who at the time of doing it, because of unsoundness of mind, is incapable of knowing the nature of the act, or that he is doing what is either wrong or contrary to law.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. DURHAM RULE (1954): \"An accused person is not criminally responsible if his unlawful act is the product of mental disease or mental defect''. Ental disease refers to a mental disorder, while mental defect refers to mental retardation. Option: C. CURREN'S RULE (1961): \"An accused person is not criminally responsible if, at the time of committing the act, he could not regulate his conduct to the requirements of the law, as a result of mental disease or defect.\" Option: D. THE AMERICAN LAW INSTITUTE (ALI) TEST (1972): \"A person is not responsible for criminal conduct if at the time of such behaviour, as a result of mental disease or defect, he lacks adequate capacity either to appreciate the criminality of his conduct or to adjust his behaviour to the requirements of the law. THE FEDERAL RULE (U.S.A.) : An accused person is not criminally responsible if, at the time of the commission of the acts constituting the offence, the defendant, as a result of severe mental disease or defect was unable to appreciate the nature and quality or the wrongfulness of his acts.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A local mad person attacked a passerby suddenly. Village people held him and handed him over to the police. All of the following are related to the legal responsibility of an insane person except", "options": [{"label": "A", "text": "MC Naughten’s Rule", "correct": false}, {"label": "B", "text": "Durham’s Rule", "correct": false}, {"label": "C", "text": "Curren’s Rule", "correct": false}, {"label": "D", "text": "Quetelet’s rule", "correct": true}], "correct_answer": "D. Quetelet’s rule", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Quetelet’s rule Quetelet's rule states that every nature-made objects present infinite variation in forms and no patterns are ever alike TESTS TO DETERMINE CRIMINAL RESPONSIBILITY ARE Option: A. McNaughten’s rule Option: B. Durham rule Option: C. Curren’s rule The Irresistible Impulse test (New Hampshire Doctrine) The American Law Institute Test The Federal Rule</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person is not responsible for his criminal acts done during all of the following except", "options": [{"label": "A", "text": "Delirium tremens", "correct": false}, {"label": "B", "text": "Hypnosis", "correct": true}, {"label": "C", "text": "Somnambulism", "correct": false}, {"label": "D", "text": "Oneiroid state", "correct": false}], "correct_answer": "B. Hypnosis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hypnosis A person is not responsible for criminal conduct if, at the time of such conduct, as a result of mental disease or defect, he lacks adequate capacity either to appreciate the criminality of his conduct or to adjust his conduct to the requirements of the law. A person is not responsible for his criminal acts during post-traumatic automatism, twilight states, and oneiroid states. This is a sleep-like condition produced by artificial means or by suggestions. During a hypnotic trance, a person may perform acts the hypnotist suggests but does not remember them afterward. A hypnotized person usually cannot be tricked into doing some immoral or dishonest act. Medical hypnosis is safe and is used in the treatment of many conditions of ill health, including states of depression and other mental disorders</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- A person is not responsible for criminal conduct, if, at the time of such conduct, as a result of mental disease or defect, he lacks adequate capacity either to appreciate the criminality of his conduct or to adjust his conduct to the requirements of the law. A person is not responsible for his criminal acts during post-traumatic automatism, twilight states, and oneiroid states.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 25 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A body was recovered from an abandoned dry well of a person who was missing for the last 20 days. Police suspected he died of starvation. In starvation, gall bladder may be:", "options": [{"label": "A", "text": "Atrophied", "correct": false}, {"label": "B", "text": "Distended", "correct": true}, {"label": "C", "text": "Gall stone", "correct": false}, {"label": "D", "text": "Normal", "correct": false}], "correct_answer": "B. Distended", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Distended</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In chronic starvation which only organ does not show a reduction in size and weight?", "options": [{"label": "A", "text": "Heart", "correct": false}, {"label": "B", "text": "Brain", "correct": true}, {"label": "C", "text": "Kidney", "correct": false}, {"label": "D", "text": "Adrenal", "correct": false}], "correct_answer": "B. Brain", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Brain In a case of starvation, there’s extreme emaciation and the general reduction in size and weight of all the organs except the brain, which is sometimes pale and soft.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In case of starvation which part of the body fat is spared till the late stage?", "options": [{"label": "A", "text": "Omental", "correct": false}, {"label": "B", "text": "Mesentery", "correct": false}, {"label": "C", "text": "Abdominal", "correct": false}, {"label": "D", "text": "Orbital", "correct": true}], "correct_answer": "D. Orbital", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Orbital Fat is almost completely absent in the subcutaneous tissues and also in the omentum, mesentery, and about internal organs, which is never seen in wasting disease. The fat of the female breast and the orbit is spared till late.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted with spasms and was diagnosed with strychnine poisoning. True about Strychnine poisoning is:", "options": [{"label": "A", "text": "All muscles affected at the same time", "correct": true}, {"label": "B", "text": "Shoulder girdle affected first", "correct": false}, {"label": "C", "text": "Pelvic girdle affected first", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "A. All muscles affected at the same time", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All muscles affected at the same time Features of strychnine poisoning:- The convulsions are preceded by such prodromal symptoms as increased acuity of perception, increased rigidity of muscles, and muscular twitchings. Convulsions are produced due to direct action on the reflex centers of the spinal cord, and affect all the muscles at a time. These are at first clonic but eventually become tonic. The mouth is covered with froth, frequently bloodstained. The convulsions are most marked in anti-gravity muscles so that the body typically arches in hyperextension (opisthotonos). Sometimes, the spasm of the abdominal muscles may bend the body forward (emprosthotonos), or to the side (pleurothotonus). Consciousness is not lost and the mind remains clear till death.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The active principle of this poison is", "options": [{"label": "A", "text": "Strychnine", "correct": true}, {"label": "B", "text": "Conine", "correct": false}, {"label": "C", "text": "Aconitine", "correct": false}, {"label": "D", "text": "Cannabinol", "correct": false}], "correct_answer": "A. Strychnine", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893904236-QTDF072005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Strychnine Strychnine (kuchila) is a powerful alkaloid obtained from the seeds of Strychnos nux vomica, and other species of Strychnos. The seeds are flat, circular discs or slightly convex on one side, concave on the other, two-and-half cm in diameter, and 6 mm in thickness. The seeds contain two principal alkaloids; strychnine and brucine one-and-half percent each. The seeds also contain a glucoside, loganin. Strychnine occurs as colourless, odourless, rhombic prisms, having an intensely bitter taste. The bark contains only brucine They are ash-grey or light-brown in colour, have a shining surface and are covered with radiating silky It competitively blocks ventral horn motor neurone postganglionic receptor sites in the spinal cord and brainstem and prevents the effects of glycine (the presumed inhibitory transmitter)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person presented with unusual spasms all over his body. Initially, it was diagnosed as tetanus but ultimately it was strychnine poisoning. All are features of strychnine poisoning except:", "options": [{"label": "A", "text": "Convulsions are most marked in anti-gravity muscles", "correct": false}, {"label": "B", "text": "All the muscles of the body are affected at a time", "correct": false}, {"label": "C", "text": "Muscles are not completely relaxed in between the fits", "correct": true}, {"label": "D", "text": "Consciousness is not lost and the mind remains clear till death", "correct": false}], "correct_answer": "C. Muscles are not completely relaxed in between the fits", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Muscles are not completely relaxed in between the fits Features of strychnine poisoning:- The convulsions are preceded by such prodromal symptoms as increased acuity of perception, increased rigidity of muscles, and muscular twitchings. Convulsions are produced due to direct action on the reflex centers of the spinal cord, and affect all the muscles at a time. These are at first clonic but eventually become tonic. The mouth is covered with froth, frequently bloodstained. The convulsions are most marked in anti-gravity muscles so that the body typically arches in hyperextension (opisthotonos). Sometimes, the spasm of the abdominal muscles may bend the body forward (emprosthotonos), or to the side (pleurothotonus). Consciousness is not lost and the mind remains clear till death.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Anterior horn cells of the spinal cord are affected in:", "options": [{"label": "A", "text": "Aconite poisoning", "correct": false}, {"label": "B", "text": "Chloral hydrate poisoning", "correct": false}, {"label": "C", "text": "Dhatura poisoning", "correct": false}, {"label": "D", "text": "Strychnine poisoning", "correct": true}], "correct_answer": "D. Strychnine poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Strychnine poisoning Strychnine competitively blocks ventral horn motor neuron postganglionic receptor sites in the spinal cord and brainstem and prevents the effects of glycine (the presumed inhibitory transmitter). Widespread inhibition in the spinal cord results in 'release' excitation. The action is particularly noted in the anterior horn cells.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which is the most common posture during a strychnine poisoning convulsion?", "options": [{"label": "A", "text": "Emprosthotonus", "correct": false}, {"label": "B", "text": "Pleurothotonus", "correct": false}, {"label": "C", "text": "Opisthotonus", "correct": true}, {"label": "D", "text": "All are equally common", "correct": false}], "correct_answer": "C. Opisthotonus", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Opisthotonus The convulsions are most marked in anti-gravity muscles so that the body typically arches in hyperextension (opisthotonos). In the supine position, the body is supported by the heels and head. The legs are adducted and extended, the arms are flexed over the chest or rigidly extended, and the hands are tightly clenched. The head is bent backward, and the whole of the body becomes rigid, often assuming a bow-like form. Opisthotonos is more common in Strychnine poisoning. Sometimes, the spasm of the abdominal muscles may bend the body forward (emprosthotonos), or to the side (pleurothotonus).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was recovered from a burning house. He was admitted with burning injuries and carbon monoxide poisoning. Mechanism of action of Carbon dioxide poisoning:", "options": [{"label": "A", "text": "Inhibition of cytochrome oxidase.", "correct": false}, {"label": "B", "text": "Combination with hemoglobin.", "correct": true}, {"label": "C", "text": "Formation of methemoglobin.", "correct": false}, {"label": "D", "text": "Prevention of tissue usage of oxygen.", "correct": false}], "correct_answer": "B. Combination with hemoglobin.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Combination with hemoglobin. The formation of carboxyhemoglobin (COHb) decreases the O2 carrying capacity of blood and impairs the release of O2 from Hb for its utilization in tissues. Through similar mechanisms, carbon monoxide decreases O2 storage in muscle cells by binding to and displacing O2 from, myoglobin.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & D. Cyanide poisons the mitochondrial electron transport chain within cells and renders the body unable to derive energy (adenosine triphosphate—ATP) from oxygen. Specifically, it binds to the a3 portion (complex IV) of cytochrome oxidase and prevents cells from using oxygen, causing rapid death. Option: C. Nitrites oxidize the iron component of red blood cells (hemoglobin), rendering them unable to carry oxygen. The resulting condition is called methemoglobinemia. Carbon monoxide CO has a 200 to 300 times higher affinity for Hb than O2, which forms COHb. Reduces O2 contain of blood and tissues. Produces Anaemic anoxia. Lab diagnosis: Spectroscopic test, Hoppe-Seyler’s test, Kunkel’s test : Post-mortem finding – Cherry-red PM staining. (COHb > 30%) Occasional blistering of skin-dependent Treatment – Immediate removal, 100% O 2 , Antidote - Hyperbaric oxygen</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "‘St.Antony’s fire’ is due to:", "options": [{"label": "A", "text": "Pyromania", "correct": false}, {"label": "B", "text": "Ergot poisoning", "correct": true}, {"label": "C", "text": "Illusion", "correct": false}, {"label": "D", "text": "Datura poisoning", "correct": false}], "correct_answer": "B. Ergot poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ergot poisoning ‘St. Antony’s fire’ is due to Ergot poisoning. It is the description given to abdominal complaints, gastritis, etc produced on consuming Ergot. Ergot refers to fungi Claviceps It grows on rye and produces alkaloids that cause ergotism Another name for ergotism: \"St. Anthony's Fire\" Symptoms: Convulsions and dry Gangrene of fingers and toes Pyromania: Pyromania is a type of impulse control disorder that is characterized by being unable to resist starting fires. Illusion: an instance of a wrong or misinterpreted perception of a sensory experience. Datura poisoning: The known symptoms of Datura stramonium intoxication include dry skin and mucosa, flushing, mydriasis, and sinus tachycardia.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 17-year-old female girl from a village was brought to the Emergency Department of a Govt. hospital in the evening. The parents who were accompanying her told the doctor on duty about her becoming unconscious and getting tremors after the ingestion of a substance that she had consumed after getting locked in her room. The doctor assuming it to be a case of attempted suicide by the ingestion of a poisonous material filed the MLC report after giving her resuscitative help. The doctor asked the nursing staff to bring the instrument as shown in the image below, which of the following statement regarding the instrument is correct?", "options": [{"label": "A", "text": "It is used for Gastric lavage, which can be done up to 24 hrs after the ingestion of the poison.", "correct": false}, {"label": "B", "text": "Boa’s tube has a mark about 50 cm from the end of the tube which has lateral openings.", "correct": true}, {"label": "C", "text": "The patient for gastric lavage should be lying in the right lateral position or lying supine.", "correct": false}, {"label": "D", "text": "It can be used in the case of all types of corrosive poisonings except Carbolic acid.", "correct": false}], "correct_answer": "B. Boa’s tube has a mark about 50 cm from the end of the tube which has lateral openings.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893904515-QTDF072012IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Boa’s tube has a mark about 50 cm from the end of the tube which has lateral openings. The given case history is suggestive of an acute case of poisoning. The doctor asked for this instrument which is known as a Stomach tube/ Ewald’s tube/ Boa’s tube or an ordinary soft rubber tube with a glass funnel at one end that can be used. Gastric lavage is useful any time within 3 hours after ingestion of a poison. It is done using a stomach tube (Ewald's or Boa's, tube) or ordinary soft, non-collapsible rubber tube of one cm. diameter and one-and-half meter length, with a glass funnel attached at one end, and a mark about 50 cm. from the other end, which should be rounded with lateral openings to avoid any injury when it is being passed. At about the midpart of the tube, there is a suction bulb, used to pump out the stomach contents. A wooden mouth gag has a hole at its mid-part to allow the passage of the tube through it. The patient should be lying on his left side or prone with head hanging over the edge of the bed, and face down supported by an assistant so that the mouth is at a lower level than the larynx so that any fluid which may leak out through the sides of the tube will not trickle down inside the larynx and trachea. The end is lubricated with olive or sweet oil, liquid paraffin, or glycerine, and is passed into the stomach by depressing the tongue with two fingers or a tongue depressor, and slowly passing it downwards through the pharynx and esophagus into the stomach, till the 50 cm mark is reached. If there are no marks on the tube, the tube should be passed for a distance equal to that measured between the bridge of the nose and the tip of the xiphoid process. Force must not be used to insert the tube. The absence of coughing and breath sounds in the funnel will confirm that the tube has not entered into the trachea. Whenever in doubt, test by keeping the free end of the tube just below a water surface. Air from the stomach is usually expelled completely in 2 to 3 expirations, whereas air from the lungs causes bubbling at each expiration. About one-fourth liter of warm water (35'C) should be passed through the funnel held high up above the patient's head. When the funnel is empty, compress the tube below it between the finger and thumb and lower it below the level of the stomach, and its contents will be emptied by siphon action on releasing the pressure on the rubber tubing. Stomach contents can be aspirated by a 20 ml. syringe. Preserve this for chemical analysis. The only absolute contraindication is corrosive poisoning (except Carbolic acid), owing to the danger of perforation.</p>\n<p><strong>Random:</strong></p><p>Explanation For All Options:- Option A . Gastric lavage is useful any time within 3 hours after ingestion of a poison. It is done using a stomach tube Ewald's or Boa's, tube. Option B . Boa's, tube is a tube of one cm. diameter and one-and-half meter in length, with a glass funnel attached at one end, and a mark of about 50 cm. from the other end, which should be rounded with lateral openings to avoid any injury when it is being passed. Option C. Patient should be lying on his left side or prone with head hanging over the edge of the bed, and face down supported by an assistant, so that the mouth is at a lower level than the larynx, so that any fluid which may leak out through the sides of the tube will not trickle down inside the larynx and trachea. Option D. The only absolute contraindication is corrosive poisoning except for Carbolic acid.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Poison is a substance which if introduced into the living body, or brought into contact with any part thereof, will produce ill health or death, by its constitutional or local effects or both. There are various laws for the control of poisons and various drugs in India, which of the following is a correct match of the various laws and their correct explanation?", "options": [{"label": "A", "text": "NDPS Act(1985) - This act has scheduled 200 psychotropic substances.", "correct": false}, {"label": "B", "text": "Drugs and Cosmetic Rules (1945) - Under this, both schedule H and L drugs must not be sold by retail, except on a prescription by a RMP.", "correct": true}, {"label": "C", "text": "Pharmacy Act (1948) - It provides for the control of the sale, supply, and distribution of drugs and exhibiting list of prices and stocks.", "correct": false}, {"label": "D", "text": "Prevention of Illicit Traffic in Narcotic Drugs and Psychotropic Substances Act (1988) - This act repels the Dangerous drugs act of 1930.", "correct": false}], "correct_answer": "B. Drugs and Cosmetic Rules (1945) - Under this, both schedule H and L drugs must not be sold by retail, except on a prescription by a RMP.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Drugs and Cosmetic Rules (1945) - Under this, both schedule H and L drugs must not be sold by retail, except on a prescription by a RMP. NARCOTIC DRUGS AND PSYCHOTROPIC SUBSTANCES (NDPS) ACT, 1985- It was amended in 1989 and 2001. It repeals three acts: The Opium Act, 1857; The Opium Act, 1878; The Dangerous Drugs Act, 1930. The Act consolidates and amends the existing laws relating to narcotic drugs, strengthens the existing laws relating to narcotic drugs, and strengthens the existing controls over drugs of abuse. \"Psychotropic substance\", means any substance, natural or synthetic, or any natural material or any salt or preparation of such substance or material, included in the list of psychotropic substances specified in a Schedule to the Act. This schedule lists 77 psychotropic substances, e.g., LSD, and THE DRUGS AND COSMETIC RULES, 1945- They were framed under the Drugs Act, of 1940, to regulate the importation of drugs, the functions and procedures of the Central Drugs Laboratory, the appointment of licensing authorities, and the manufacture, distribution, and sale of drugs. These rules have classified drugs into Schedules as follows. Schedule C: Biological and special products; E: List of poisons; F: Vaccines and sera; G: Hormone preparations; H: Drugs (poisons to be sold only on the prescription of a registered medical practitioner); J: List of diseases for the cure of which no drug should be advertised; L: Antibiotics, antihistamines, and other recent chemotherapeutic agents. Both Schedule H and L drugs must not be sold by retail, except on a prescription by a registered medical practitioner THE PHARMACY ACT, 1948: It was passed in order to make better provision for the regulation of the profession of pharmacy and to constitute the Central Council of Pharmacy and State Councils of Pharmacy. The object of this Act is to allow only registered pharmacists to compound, prepare, mix, or dispense any medicine on the prescription of a medical practitioner. This does not apply to the dispensing by a doctor for his own patients. PREVENTION OF ILLICIT TRAFFIC IN NARCOTIC DRUGS AND PSYCHOTROPIC SUBSTANCES ACT, 1988- If a person produces, possesses, transports, imports, exports, sells, purchases, or uses any narcotic drug or psychotropic substance except ganja, he shall be punishable with imprisonment. Drugs and Cosmetic Rules (1945) - Under this both schedule H and L drugs must not be sold by retail, except on a prescription by a RMP.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Narcotic Drugs and Psychotropic Substances(NDPS) ACT has scheduled lists of 77 psychotropic substances, e.g., LSD, and Option: C. The Pharmacy Act, of 1948 allows only registered pharmacists to compound, prepare, mix, or dispense any medicine on the prescription of a medical practitioner. Option: D. Prevention of Illicit Traffic in Narcotic Drugs and Psychotropic Substances Act, 1988 controls if a person produces, possesses, transports, imports, exports, sells, purchases, or uses any narcotic drug or psychotropic substance except ganja, he shall be punishable with imprisonment.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A case of poisoning with an unknown substance was reported when a 45-year-old man complained of nausea, vomiting, abdominal cramps, and dizziness along with fits of seizure. It was assumed to be a case of homicidal poisoning on the basis of his history of eating at a business meeting with one of his rivalry. Which of the following is a correct statement regarding the various types of poisoning given below?", "options": [{"label": "A", "text": "Ideal Homicidal poison - Antidote should be available.", "correct": false}, {"label": "B", "text": "Suicidal poison - Endrin and OPCs are commonly used.", "correct": true}, {"label": "C", "text": "Abortifacient - Datura, chloral hydrate.", "correct": false}, {"label": "D", "text": "Cattle poison - Calotropis, Oleanders.", "correct": false}], "correct_answer": "B. Suicidal poison - Endrin and OPCs are commonly used.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Suicidal poison - Endrin and OPCs are commonly used. Poison is any substance that when administered or brought into contact with the body, produces ill effects or death by its constitutional or local actions or both. Ideal Homicidal Poison - The characteristics of an ideal homicidal poison are, it must be cheap, easily available, colourless, odourless, and tasteless, capable of being administered, either in food, drink, or medicine, without producing any obvious change to prevent suspicion, highly toxic, signs and symptoms should resemble a natural disease or the serious ill-effects should be delayed sufficiently long for the accused to escape suspicion, there should not be any antidote, there should be no postmortem changes, should not be detected by chemical tests, or other methods, and must be rapidly destroyed or made undetectable in the body. Organic compounds of fluorine (used as rodenticides), and thallium satisfy several of the above criteria. Arsenic and aconite are commonly used. Ideal Suicidal Poison - The characteristics of an ideal suicidal poison are that it should be cheap, easily available, highly toxic, tasteless or of pleasant taste, capable of being easily taken in food or drink, and capable of producing painless death. Opium and barbiturates satisfy several of the above criteria. Organophosphorus compounds and endrin are commonly used as suicidal poisons. Stupefying - Datura, Cannabis indica , and chloral hydrate makes someone unable to think clearly. Abortifacient - Calotropis, oleanders, aconite, croton, semecarpus, cantharides, ergot, lead, arsenic, mercury, potassium permanganate, etc. are used to terminate a pregnancy. Cattle Poisoning - The usual motive is the destruction of cattle of an enemy, or to obtain the hides. The usual poisons are abrus precatorius, oleanders, calotropis, organophosphorus, arsenic, aconite, strychnine, zinc phosphide, nitrate, etc.</p>\n<p><strong>Random:</strong></p><p>Explanation For All Options:- Option: A. For an ideal homicidal poison, there should not be any antidote available. Option: B. Ideal Suicidal Poison as Opium and barbiturates satisfy several of the criteria for it. Organophosphorus compounds and endrin are commonly used as suicidal poisons. Ideal Suicidal Poison Should be cheap and easily available Should be tasteless or be of pleasant taste Capable of being administered with food materials Should be highly toxic Should be capable of producing painless death g. Opium and Barbiturates, but commonly used are Organophosphorus compounds and Endrin Option: C. Abortifacient - Calotropis, oleanders, aconite, croton, sem ecarpus, cantharides, ergot, lead, arsenic, mercury, potassium permanganate, etc. are used to terminate a pregnancy. Option: D. Cattle Poisoning - The usual motive is the destruction of cattle of an enemy, or to obtain the hides. The usual poisons are abrus precatorius, oleanders, calotropis, organophosphorus, arsenic, aconite, strychnine, zinc phosphide, nitrate, etc.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You were the PGY2 resident in the Forensic department of a Medical college. A case of poisoning presented in the early morning which succumbed to death in the hospital only and now you were asked to perform the autopsy of the body. After making an MLC report you did the autopsy and preserved the viscera and sent it for further investigation about the poison. Which of the following statement is correct regarding the autopsy findings?", "options": [{"label": "A", "text": "Garlicky smell is found in the case of ethanol, and chloroform poisoning.", "correct": false}, {"label": "B", "text": "Magenstrasse is the pathway of acids or alkalis which starts along the lesser curvature of the stomach.", "correct": true}, {"label": "C", "text": "Hyperaemia of the mucous membrane caused by an irritant poison is usually generalised and yellow in colour.", "correct": false}, {"label": "D", "text": "After the autopsy the ligated stomach is sent for the examination of its contents directly in a jar with a lid.", "correct": false}], "correct_answer": "B. Magenstrasse is the pathway of acids or alkalis which starts along the lesser curvature of the stomach.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Magenstrasse is the pathway of acids or alkalis which starts along the lesser curvature of the stomach. The information from the inquest report and from the relatives is obtained before starting the autopsy for diagnosing the case of poisoning. The findings of the autopsy are :- External findings show the surface of the body and the clothes may show stains or marks of vomit, feces, or the poison itself. The colour changes in the corroded skin and mucous membrane are: sulphuric and hydrochloric acid- grey, becoming black from blood; nitric acid- brown; hydrofluoric acid- reddish-brown; carbolic acid- greyish-white; oxalic acid- grey, blackened by blood; cresols- brown, leathery; caustic alkalis: greyish-white. The skin may be dark-brown or yellow in phosphorus and acute copper poisoning; cherry-red in poisoning by carbon monoxide; chacolate-coloured in cases of death from poisoning by nitrites, aniline, nitrobenzene, acetanilide, bromates, chlorates, etc. due to the formation of methaemoglobin. Smell about the mouth and nose may be garlic-like in Phosphorus, arsine gas, arsenic (breath and perspiration), thallium, tellurium, selenium, dimethylsulphoxide, parathion, malathion; sweet or fruity in Ethanol, chloroform, nitrites. Any evidence of marks of violence, such as bruises, or wounds of any nature, may suggest some form of death other than poison. The bodies of persons poisoned are not more rapidly decomposed than those of others. Some poisons may delay the action of the putrefactive bacteria to some extent. Internal findings show smell: On opening the body, note any peculiar smell. The skull should be opened first to detect unusual odours in the brain tissues because such odours are masked by the opening of the body cavities. This is useful in cyanide, alcohol, phenol, cresol, ether, chloroform, and camphor poisoning. Stomach shows toxic substances may be held in high concentrations in the rugae and crypts of the mucosa, or even in the blood in the actual stomach wall. The pathway of acids and alkalis in the food-filled stomach starts along the lesser curvature of the stomach and leads to the pylorus, which explains the location of the greatest damage in the food-filled stomach. Hyperaemia of the mucous membrane caused by an irritant poison is usually patchy and of a deep crimson colour. The ridges are more involved in poisoning than in disease. Oesophagus shows marked softening and desquamation of the mucous membrane by the corrosives. In acute cantharidin poisoning, the mucous membrane is often swollen and engorged and may show patches of ulceration. The ligatured stomach should never be sent for analysis without being opened, as putrefaction may obscure changes in the mucous membrane, and the gases produced may result in the lid of the jar being forced off in transit. The stomach is opened along its greater curvature in a clean porcelain dish. The wall is examined for fragments of poison adhered to it, such as powdered poisons, fragments of capsules, starch from tablets, fragments of leaves or fruit, cantharides, etc. The contents must be carefully observed and written notes made, regarding the volume, colour, and contents, including food.</p>\n<p><strong>Random:</strong></p><p>Explanation For All Options:- Option: A. Garlic-like smell is seen in Phosphorus, arsine gas, arsenic (breath and perspiration). thallium, tellurium, selenium, dimethylsulphoxide, parathion, malathion like poisons. Option: B. Magenstrasse is the pathway of acids or alkalis which starts along the lesser curvature of the stomach and leads to the pylorus, which explains the location of greatest damage in food-filled stomach. Option: C. Hyperaemia of the mucous membrane caused by an irritant poison is usually patchy and of a deep crimson colour. Option: D. The ligatured stomach should never be sent for analysis without being opened, as putrefaction may obscure changes in the mucous membrane, and the gases produced may result in the lid of the jar being forced off in transit. The stomach is opened along its greater curvature in a clean porcelain dish.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 25-years-old male presented to the ER of a Govt. hospital with complaints of episodes of unconsciousness, nausea, abdominal cramps, convulsions, and hemoptysis after the consumption of an Insecticide which was used by his family in the fields. The resident doctor performed the gastric lavage and started him on a specific antidote and oxygen therapy. His investigation reports were sent and reports were awaited. Which of the following is a correct statement regarding the treatment option which is to be done in case of poisoning?", "options": [{"label": "A", "text": "Gastric lavage using Ewald's tube with 1:5000 potassium permanganate and water.", "correct": true}, {"label": "B", "text": "Emetics should be used after the ingestion of a CNS stimulant.", "correct": false}, {"label": "C", "text": "Multidose-activated charcoal facilitates the passage of substances from the intestinal lumen into the plasma.", "correct": false}, {"label": "D", "text": "EDTA neutralises poison by mechanical action or prevents their absorption.", "correct": false}], "correct_answer": "A. Gastric lavage using Ewald's tube with 1:5000 potassium permanganate and water.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Gastric lavage using Ewald's tube with 1:5000 potassium permanganate and water. In case of any poisoning, the doctor must work to maintain ABC(Airway, Breathing, Circulation) first and then provide any other symptomatic or specific treatment. The protocol for poisoning case management is as- Immediate resuscitation - by maintaining the ABC first and then working for CNS depression management. Removal of unabsorbed poison from the body - If the poison is inhaled as a gas, the patient must be removed into the fresh air, and artificial respiration and oxygen (six to eight liters per minute) should be given. If the poison has been injected subcutaneously from a bite or an injection, a tight ligature should be applied immediately above the wound, which must be loosened for one minute after every ten minutes, to prevent gangrene. The wound should be excised, the poison sucked out, and the poison neutralised by a suitable chemical substance. Gastric lavage is useful any time within 3 hours after ingestion of a poison. It is done using a stomach tube (Ewald's or Boa's, tube) or ordinary soft, non-collapsible rubber tube of one cm. diameter and one-and-half metre length, with a glass funnel attached at one end, and a mark about 50 cm. from the other end, which should be rounded with lateral openings to avoid any injury when it is being passed. At about the midpart of the tube, there is a suction bulb, used to pump out the stomach contents. A wooden mouth gag has a hole at its mid-part to allow the passage of the tube through it. Emetics should be used only if there is difficulty in obtaining or using a stomach tube. Vomiting can be produced only if the medullary centres are still responsive. It is contraindicated in case of ingestion of a CNS stimulant, because further stimulation associated with vomiting may produce convulsions. Administration of Antidotes - Mechanical antidote (activated charcoal, bulky food, Multidose activated charcoal facilitates the passage of substances from plasma into the intestinal lumen (by creating a concentration gradient between the blood and bowel fluid)); Chemical antidote(albumin, potassium permanganate, copper sulphate); Physiological antidote (E.D.T.A.(ethylenediaminetetraacetic acid) is a chelating agent and is effective in the lead, mercury, copper, cobalt, cadmium, iron, and nickel poisoning), BAL, and DMSA). Elimination of poison by excretion - (Renal excretion, purging, forced alkaline diuresis, hemodialysis). Symptomatic treatment and follow-up.</p>\n<p><strong>Random:</strong></p><p>Explanation For All Options:- Option: A. Gastric lavage is useful any time within 3 hours after ingestion of a poison. It is done using a stomach tube (Ewald's or Boa's, tube) or ordinary soft, non-collapsible rubber tube of one cm. diameter and one-and-half meter length, with a glass funnel attached at one end, and a mark about 50 cm. from the other end, which should be rounded with lateral openings to avoid any injury when it is being passed. At about the midpart of the tube, there is a suction bulb, used to pump out the stomach contents. Option: B. Emetics should be used only if there is difficulty in obtaining or using a stomach tube. Vomiting can be produced only if the medullary centers are still responsive. It is contraindicated in case of ingestion of a CNS stimulant, because further stimulation associated with vomiting may produce convulsions. Options: C. Multidose-activated charcoal facilitates the passage of substances from plasma into the intestinal lumen (by creating a concentration gradient between the blood and bowel fluid), where the concentration of toxin has been significantly lowered by intraluminal charcoal adsorption, and significantly decreases the half-life of several drugs. Option: D. D.T.A.(ethylenediaminetetraacetic acid) is a chelating agent and is a Physiological antidote that is effective in the lead, mercury, copper, cobalt, cadmium, iron, and nickel poisoning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 25 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A hair has been recovered from a crime scene. It was subjected to microscopic examination. Identify the human hair:", "options": [{"label": "A", "text": "A", "correct": true}, {"label": "B", "text": "B", "correct": false}, {"label": "C", "text": "C", "correct": false}, {"label": "D", "text": "D", "correct": false}], "correct_answer": "A. A", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891839908-QTDF012001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A Difference between human hair & animal hair Points Human hair Animal hair 1.General character 1. Fine & thin 1.Coarse & thick 2.Cuticle 2.Cuticular scales are soft, thin & flattened 2.Cuticular scales are very marked with large & step like or wavy projections 3.Cortex 3. Well striated, 4-10 time as broad as medulla 3.Thin, rarely more than twice as broad as medulla. 4.Medulla 4.Thiner, even may be absent. 4. Wider 5.Pigment 5.More towards the periphery of the cortex 5.It may be central, peripheral or uniform 6.Shaft diameter 6. Usually 50-150μm 6. Either <25 or>3000 μm 7. Precipitin test 7.Specific for human being 7.Specific for animal</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Blood stains are important biological evidence that needs a thorough analysis. Test which confirms whether blood stain is of human origin:", "options": [{"label": "A", "text": "Magnus’s test", "correct": false}, {"label": "B", "text": "Takayama test", "correct": false}, {"label": "C", "text": "Precipitin test", "correct": true}, {"label": "D", "text": "Teichmann’s test", "correct": false}], "correct_answer": "C. Precipitin test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Precipitin test The Precipitin test is an antigen-antibody reaction test used to distinguish between species (human vs. animal).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Magnus test (ligature test) is a test for circulation - fingers fail to show congestion & swelling to a ligature applied at their base. Option: B . Takayama test = Hemochromogen crystal test - is a test to identify blood stains. Takayama reagent (NaOH+pyridine+glu+H2O) gives pink feathery crystals of hemochromogen or reduced alkaline hematin in clusters. Option: D. Teichmann’s test =Hemin crystal test is also a test to identify blood stains- NaCl+glacial acetic acid → heat, yellow-red to brownish-black rhombic crystals of hemin/hematin chloride, arranged singly or in clusters.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Blood stains are important biological evidence that needs a thorough analysis. All are tests done on blood EXCEPT:", "options": [{"label": "A", "text": "Acid Phosphatase test", "correct": true}, {"label": "B", "text": "Benzidine test", "correct": false}, {"label": "C", "text": "Hemochromogen test", "correct": false}, {"label": "D", "text": "Teichmann’s test", "correct": false}], "correct_answer": "A. Acid Phosphatase test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Acid Phosphatase test The acid phosphatase test is used to detect seminal fluid and not blood. (Its level of > 25 kA Unit is specific for the test, and Undiluted semen has an acid phosphatase activity of 340 – 360 Bodansky U/ml; it is higher in humans than It is based on the prostatic secretion part of seminal fluid.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B, C & D: Benzidine test is a screening test for blood stains, and the Hemochromogen crystal (Takayama) test and Teichmann’s (Hemin crystal) tests are for confirmation of blood stains.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A blood-stained cloth was submitted for analysis in case of homicide. Investigation of choice for blood grouping (human vs. animal) in an old blood stain on the cloth is:", "options": [{"label": "A", "text": "Precipitin test", "correct": true}, {"label": "B", "text": "Benzidine test", "correct": false}, {"label": "C", "text": "Acid elution test", "correct": false}, {"label": "D", "text": "Hemin crystal test", "correct": false}], "correct_answer": "A. Precipitin test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Precipitin test Precipitin test detects antigen-antibody reaction, used for differentiating human vs. non-human grouping.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B, C & D: All other tests i.e., Benzidine, Acid elution, Hemin crystal test, are used to detect Haemoglobin only.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A blood-stained cloth was submitted for analysis in case of homicide. The most specific test to detect blood stains is:", "options": [{"label": "A", "text": "Benzidine test", "correct": false}, {"label": "B", "text": "Teichmann’s test", "correct": false}, {"label": "C", "text": "Takayama test", "correct": false}, {"label": "D", "text": "Spectroscopic test", "correct": true}], "correct_answer": "D. Spectroscopic test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Spectroscopic test The spectroscopic test is the most specific for blood stains. It is the most delicate and reliable test for detecting the presence of blood in both recent and old stains. Less than 0.1 mg. of blood is sufficient. The blood stain is dissolved in water, normal saline, or dilute ammonia and placed in a small glass test tube, which is then kept between the spectroscope and the light source. The blood extract must be diluted,d and if turbid, it should be filtered. The solution of the blood absorbs some of the rays from the spectrum, producing characteristic dark absorption bands that vary with the type of blood pigment present.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Benzidine test- (sat. benzidine in glacial acetic acid + 10v H2O2), intense dark blue color, the blood of any age, blood exposed to heat/cold, treated with detergents, most sensitive- sensitivity 1 in 3 lakhs, more Negative value, Weakly +ve by pus, saliva, milk, rust, formalin, bacteria, oxidizing agents, vegetables. Option: B. Hemin crystal test=Teichmann’s test- NaCl+glacial acetic acid→heat, yellow-red to brownish-black rhombic crystals of hemin/hematin chloride, arranged singly or in clusters. Option:C. Hemochromogen crystal test=Takayama test- NaOH+pyridine+glu+H2O, pink feathery crystals of hemochromogen or reduced alkaline hematin in clusters.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A person hanging himself from a· branch of a tree, the branch breaks and the person dies due to complications from the fall. This is called", "options": [{"label": "A", "text": "Complex suicide", "correct": false}, {"label": "B", "text": "Complicated suicide", "correct": true}, {"label": "C", "text": "Typical suicide", "correct": false}, {"label": "D", "text": "Atypical Suicide", "correct": false}], "correct_answer": "B. Complicated suicide", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Complicated suicide Complicated suicide: When during the original suicidal method, unintentional trauma occurs which leads to death, e.g. a person hanging himself from a branch of a tree, the branch breaks, and the person dies due to complications from the fall</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options: - Option: A. Complex suicide: The person plans more than one method of suicide to make sure that death will occur. Option: C. Typical hanging: The ligature runs from the midline above the thyroid cartilage symmetrically upward on both sides of the neck to the occipital region. The knot is over the central part of the back of the neck. Option: D. Atypical Hanging: The knot is anywhere other than on the occiput, i.e. on the right or left side or front of the neck.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Police rushed to a site after getting information about a ruckus created by a group of people. Gradually a crowd accumulated at the site. What does the Image show:", "options": [{"label": "A", "text": "Suicidal hanging", "correct": false}, {"label": "B", "text": "Accidental Hanging", "correct": false}, {"label": "C", "text": "Homicidal Hanging", "correct": true}, {"label": "D", "text": "Postmortem hanging", "correct": false}], "correct_answer": "C. Homicidal Hanging", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892485509-QTDF028003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Homicidal Hanging HOMICIDAL HANGING: It is extremely rare. It is difficult for a single assailant to carry it out unless the victim becomes unconscious by injury or by a drug, is taken unaware, or is a child or a very weak person. Homicide should be suspected. Where there are signs of violence or disorder of furniture or other objects, Where the clothing of the deceased is torn or disarranged Where there are injuries, either offensive or defensive. In all doubtful cases, circumstantial evidence is essential. If an individual is suspended upside down for a long time, death can occur in a few hours to a day from acute cardiac or respiratory failure or a combination of both.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. SUICIDAL HANGING - A typical method of self-suspension is to attach a rope to a high point, such as a beam, window-casing, ceiling fan, a branch of a tree, etc. The lower end is formed into either a fixed loop or a slip-knot placed around the neck. The victim stands on a stool, chair or other platform and jumps off or kicks away the support, due to which the body is suspended. The body must be in a position compatible with self-suspension. Option: B. ACCIDENTAL HANGING : It is seen in children during play while imitating judicial hanging. Some padding between the ligature and neck suggests an accident. Workmen falling from scaffolding may be hanged by becoming entangled in ropes. When boys climb trees or railings, they may lose their foothold, and in falling, some garment is caught by a branch of a tree or bar and is drawn tight around the neck. Infants wearing restraining apparatus may wriggle partly out of it and become asphyxiated by its tightening around their neck as they try to crawl away or fall over the side of the bed. The ligature need not completely encircle the neck to cause death. It is sufficient if applied beneath the chin to compress the sides of the neck, e.g., suspension of the chin by the steering wheel of a motor car, the tailboard of a lorry or cart, the edge of a sofa or the arm of the chair. A person who slips when descending a ladder may be suspended by one of its rungs, or a slip on a staircase may result in suspension on the edge of one of the treads. It may be associated with abnormal sexual behaviour. Option D: Postmortem Hanging : A person may be murdered, and the dead body suspended to simulate suicide. A ligature applied to the neck within two hours of death will produce a ligature mark.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "On dissection of the neck, the doctor found a fracture of the hyoid bone. Outward compression Hyoid fracture is most common in;", "options": [{"label": "A", "text": "Hanging", "correct": true}, {"label": "B", "text": "Ligature Strangulation", "correct": false}, {"label": "C", "text": "Throttling", "correct": false}, {"label": "D", "text": "Choking", "correct": false}], "correct_answer": "A. Hanging", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hanging In hanging cases, the hyoid bone is forced directly backwards, due to which the divergence of greater horns is increased, which may fracture with the outward displacement of the posterior small fragment. In such cases, the periosteum is only torn on the inner side of the fracture so that the fragment can be easily moved outwards. Still, the inward movement is limited to the normal position only. Like the inward compression fracture, anteroposterior compression fracture may occur either in the greater horn or at its junction with the body, which may be bilateral. When compression is severe, the small fragment may completely detach from the bone and lie either medially or laterally to the rest of the bone.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C & D: Hyoid fracture is not common in strangulation, choking or throttling. Hence these options are not correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In a case, an autopsy showed a haemorrhage in the lumbar vertebral region. Simon’s sign is seen in the following:", "options": [{"label": "A", "text": "Hanging", "correct": true}, {"label": "B", "text": "Fall from height", "correct": false}, {"label": "C", "text": "Drowning", "correct": false}, {"label": "D", "text": "Trauma with a head injury", "correct": false}], "correct_answer": "A. Hanging", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hanging Bleeding into the outer layers of the intervertebral discs (red stripes in between the vertebral bodies) of lumbar vertebrae (Simon's haemorrhages) may be seen in bodies suspended for a long time a case of hanging.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options : B, C & D. Simon's Sign is seen in bodies suspended for a long time, as in hanging. Hence it cannot be seen in a fall from height, Drowning or head injury.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A victim at the autopsy table had an eye wide open with dilated pupil. ‘Le facies sympathique’ is seen?", "options": [{"label": "A", "text": "At the side of the knot in hanging", "correct": true}, {"label": "B", "text": "Usually in strangulation", "correct": false}, {"label": "C", "text": "Opposite the side of the knot in hanging", "correct": false}, {"label": "D", "text": "Any of the above", "correct": false}], "correct_answer": "A. At the side of the knot in hanging", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>At the side of the knot in hanging If the ligature knot presses on the cervical sympathetic, the eye on the same side may remain open and its pupil dilated, called le facie sympathique It indicates antemortem hanging.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B: Le facies sympathique is usually seen in hanging and not in strangulation. Option: C. Le facies sympathique is seen hanging at the side of the knot due to the ligature knot's compression of the cervical sympathetic and not on the opposite side.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was found hanging with multiple injuries over the body. The police wanted to know whether this was a case of hanging after death. Sign of antemortem hanging is?", "options": [{"label": "A", "text": "Ligature mark", "correct": false}, {"label": "B", "text": "Eye is open", "correct": true}, {"label": "C", "text": "Fracture of the hyoid", "correct": false}, {"label": "D", "text": "Tardieu spot", "correct": false}], "correct_answer": "B. Eye is open", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Eye is open Eye signs in a case of hanging: - The conjunctivae are usually congested. When the knot is in front of one ear, conjunctival haemorrhages may be one-sided. The eyes are closed or partially open, and the pupils are usually dilated. If the ligature knot presses on the cervical sympathetic, the eye on the same side may remain open and its pupil dilated.(le facie sympathique). It indicates antemortem hanging.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D. Ligature marks, hyoid fractures and Tardieu spots can be observed in both antemortem and postmortem hanging. Hence are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was found hanging from a tree in a forest. In a typical hanging, the knot of the ligature is placed:", "options": [{"label": "A", "text": "Below chin in the midline", "correct": false}, {"label": "B", "text": "At the angle of the mandible on either side", "correct": false}, {"label": "C", "text": "Over the mastoid bone on either side", "correct": false}, {"label": "D", "text": "At the nape of the neck on the back", "correct": true}], "correct_answer": "D. At the nape of the neck on the back", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>At the nape of the neck on the back Typical hanging: The ligature runs from the midline above the thyroid cartilage symmetrically upward on both sides of the neck to the occipital region, and the knot is over the central part of the back of the neck.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options : A, B & C. Below the chin, at the angle of the mandible, over the mastoid bone or any other site other than the nape of the neck on the back is known as atypical hanging. Hence these options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In which type of hanging, constricting force is the weight of the whole body:", "options": [{"label": "A", "text": "Typical hanging", "correct": false}, {"label": "B", "text": "Atypical hanging", "correct": false}, {"label": "C", "text": "Complete hanging", "correct": true}, {"label": "D", "text": "Partial hanging", "correct": false}], "correct_answer": "C. Complete hanging", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Complete hanging Complete hanging: The body is completely suspended without any part of the body touching the ground.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A & B. Typical and atypical hanging may be complete or partial. Hence are not the correct answers. Option: D. The body's weight can act as a constricting force only when it's suspended completely. Hence partial hanging cannot be the answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body was found lying on the floor in hanging condition with the door knob of the door. Partial hanging is almost always:", "options": [{"label": "A", "text": "Accidental", "correct": false}, {"label": "B", "text": "Suicidal", "correct": true}, {"label": "C", "text": "Homicidal", "correct": false}, {"label": "D", "text": "Either homicidal or accidental, never suicidal", "correct": false}], "correct_answer": "B. Suicidal", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Suicidal 'Partial hanging':- The bodies are partially suspended, the toes or feet touching the ground, or is in a sitting, kneeling, lying down, prone or any other posture, with only the head and chest off the ground. The head's weight (5 to 6 kg), chest and arms act as the constricting force. The body's whole weight is unnecessary, and only a comparatively slight force is enough to produce death. Depending on the position of the knot: Typical hanging: The ligature runs from the midline above the thyroid cartilage symmetrically upward on both sides of the neck to the occipital region. The knot is over the central part of the back of the neck. Atypical Hanging: The knot is anywhere other than on the occiput, i.e. on the right or left side or front of the neck. Partial hanging is usually suicidal.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D. Since partial hanging is almost always suicidal, accidental and homicidal hanging cannot be the correct answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A prisoner was set to hang by the neck. The executioner has prepared the rope diligently. The position of the knot in judicial hanging is:", "options": [{"label": "A", "text": "Over the occipital protuberance", "correct": false}, {"label": "B", "text": "Angle of mandible", "correct": true}, {"label": "C", "text": "Below the chin", "correct": false}, {"label": "D", "text": "Choice of hangman", "correct": false}], "correct_answer": "B. Angle of mandible", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Angle of mandible In India, the legal death sentence is carried out by hanging the criminal. The face of the person is covered with a dark mask, and he is made to stand on a platform above trapdoors which open downwards when a bolt is drawn. A rope to allow a drop of five to seven metres, according to the person's weight, build and age, is looped around the neck, with the knot under the angle of the left side of the mandible. The placement of the knot beneath the chin, in the submental position, is more effective. On drawing the bolt, the person drops to the length of the rope. The sudden stoppage of the moving body associated with the position of the knot causes the head to be jerked violently.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D. In India, legal death is carried out by hanging the criminal with a knot at the angle of the mandible. Since this is the custom, all other answers are wrong.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A man was found hanging in his room in a bizarre condition with naked photographs and pornography lying beside the body. Sexual asphyxias are commonly associated with:", "options": [{"label": "A", "text": "Partial hanging", "correct": true}, {"label": "B", "text": "Complete hanging", "correct": false}, {"label": "C", "text": "Smothering", "correct": false}, {"label": "D", "text": "Strangulation", "correct": false}], "correct_answer": "A. Partial hanging", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Partial hanging Hanging is the most frequent form seen in sexual asphyxias. The neck is protected by padding between the neck and the ligature. The ligature is passed around the neck as a running noose, the free end of which is tied to a limb or a fixed object. The weight of the body is used to control the pressure. The free end of the ligature may be tied to the wrists or ankles, which are usually tied together. The noose can be tightened by extending the arms or legs, and when consciousness is lost, the relaxation of the limbs releases pressure on the neck.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In a case of hanging hyoid bone fracture was found at autopsy. Which type of hyoid fracture is seen commonly in hanging?", "options": [{"label": "A", "text": "Antero-posterior compression", "correct": true}, {"label": "B", "text": "Inward compression", "correct": false}, {"label": "C", "text": "Avulsion", "correct": false}, {"label": "D", "text": "Combination of A& C", "correct": false}], "correct_answer": "A. Antero-posterior compression", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Antero-posterior compression Anteroposterior Compression Fractures are usually seen in cases of hanging, The hyoid bone is forced directly backwards, so the divergence of greater horns is increased, which may fracture with the outward displacement of the posterior small fragment.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. In such cases, the periosteum is only torn on the inner side of the fracture so that the fragment can be easily moved outwards. Still, the inward movement is limited to the normal position only. Option: C. Like the inward compression fracture, anteroposterior compression fracture may occur either in the greater horn or at its junction with the body, which may be bilateral. When compression is severe, the small fragment may completely detach from the bone and lie either medially or laterally to the rest of the bone. In such cases, in situ examination of the hyoid bone in the neck only will decide whether the fracture was inward or outward. Outward fractures of the greater horn of the hyoid bone are seen in ligature strangulations, run-over motor vehicle accidents blow on the front of the neck, etc. In these cases, the hyoid bone is grossly fractured with an outward displacement of the fragments and multiple fractures of other structures are also found.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 22 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A person was admitted with chronic metal poisoning. He was complaining of a metallic taste and constipation. Which heavy metal causes constipation:", "options": [{"label": "A", "text": "Lead", "correct": true}, {"label": "B", "text": "Mercury", "correct": false}, {"label": "C", "text": "Copper", "correct": false}, {"label": "D", "text": "Arsenic", "correct": false}], "correct_answer": "A. Lead", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lead Colic and Constipation :- It is usually a later symptom. Colic of the intestines, ureters, uterus and blood vessels occur in 85% of cases. The colic occurs at night and the pain may be very severe. Individual attacks last only a few minutes but may recur for several days or weeks. Constipation is usual but diarrhoea or vomiting may occur.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Gastric lavage of a person brought to casualty with an alleged history of unknown poisoning turns black when heated with Silver Nitrate solution. The most likely poison involved is:", "options": [{"label": "A", "text": "Arsenic", "correct": false}, {"label": "B", "text": "Aluminium phosphide", "correct": true}, {"label": "C", "text": "Opium", "correct": false}, {"label": "D", "text": "Malathion", "correct": false}], "correct_answer": "B. Aluminium phosphide", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Aluminium phosphide CHEMICAL TESTS FOR ANALYSIS OF ALUMINIUM PHOSPHIDE:- Five ml. of gastric aspirate and 15 ml. of water are put in a flask and the mouth is covered with a filter paper impregnated with silver nitrate (0.1N). The flask is heated at 50°C for 15 to 20 minutes. If phosphine is present, the filter paper turns black. A piece of filter paper impregnated with 0.1 N silver nitrate solution is used in the form of a mask through which the patient breathes for 5 to 10 minutes. The filter paper turns black if phosphine is present. The filter paper impregnated with AgN03 (0.1N) is used in the form of a face mask and the patient is asked to breathe in and out of this filter paper for 15 to 20 minutes. The presence of PH3 is indicated by the blackening of filter paper. In breath, the test is positive only in patients who have ingested more than six gm of ALP</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A farmer’s wife was admitted after she took a pill of aluminium phosphide in the heat of an argument. In aluminum phosphide poisoning which is not true", "options": [{"label": "A", "text": "Phosphine formation", "correct": false}, {"label": "B", "text": "Cytochrome oxidase inhibition", "correct": false}, {"label": "C", "text": "Accumulation of acetylcholine at the neuro-muscular junction", "correct": true}, {"label": "D", "text": "Metabolic acidosis", "correct": false}], "correct_answer": "C. Accumulation of acetylcholine at the neuro-muscular junction", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Accumulation of acetylcholine at the neuro-muscular junction Accumulation of acetylcholine is seen in anticholinesterase poisoning giving rise to cholinergic and nicotinic symptoms and signs. Aluminium phosphide (ALP) is a solid fumigant pesticide, insecticide and rodenticide. Has the capacity to liberate one gram of phosphine (PH3). On coming in contact with moisture ALP liberates phosphine. Phosphine is a systemic poison and affects all organs of the body. Phosphine inhibits respiratory chain enzymes and has cytotoxic action. It acts by inhibiting the electron transport resulting from preferential inhibition of cytochrome oxidase. Metabolic acidosis should be corrected with i.v. sodium carbonate. Peritoneal or hemodialysis is useful.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Desferrioxamine is the specific antidote for the poisoning of:", "options": [{"label": "A", "text": "Arsenic", "correct": false}, {"label": "B", "text": "Lead", "correct": false}, {"label": "C", "text": "Copper", "correct": false}, {"label": "D", "text": "Iron", "correct": true}], "correct_answer": "D. Iron", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Iron Desferrioxamine:- It contains trivalent iron as a chelate and is very useful in acute iron poisoning. 8 to 12 g. is given orally daily to absorb iron in the stomach. Two g in five per cent of laevulose solution is given i.v. to bind absorbed iron, repeated twelve hourly if necessary. It is also used to promote the removal of radioactive heavy metals.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following poison can be detected in burnt bones?", "options": [{"label": "A", "text": "Arsenic", "correct": true}, {"label": "B", "text": "Lead", "correct": false}, {"label": "C", "text": "Copper", "correct": false}, {"label": "D", "text": "Iron", "correct": false}], "correct_answer": "A. Arsenic", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Arsenic Arsenic can be detected in completely decomposed bodies, can be found in bones, hair and nails for several years, and can be detected in charred bones or ashes.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The velvety appearance of the stomach is seen in acute poisoning with:", "options": [{"label": "A", "text": "Copper sulphate", "correct": false}, {"label": "B", "text": "Arsenic", "correct": true}, {"label": "C", "text": "Barbiturate", "correct": false}, {"label": "D", "text": "Lead", "correct": false}], "correct_answer": "B. Arsenic", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Arsenic The stomach mucosa resembles red velvet. Small acute ulcerations or large erosions may be found, especially at the pyloric end. A mass of sticky mucus covers the mucosa in which particles of arsenic may be seen, in case of acute poisoning of arsenic.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Chronic arsenic poisoning causes:", "options": [{"label": "A", "text": "Pure sensory neuropathy", "correct": false}, {"label": "B", "text": "Pure motor neuropathy", "correct": false}, {"label": "C", "text": "Mixed sensory and motor neuropathy", "correct": true}, {"label": "D", "text": "Hyperkeratosis of palms and soles", "correct": false}], "correct_answer": "C. Mixed sensory and motor neuropathy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mixed sensory and motor neuropathy Peripheral neuropathy in a case of chronic arsenic poisoning: Sensory and motor polyneuritis (sensory symptoms usually predominate) manifesting as numbness and tingling in a ‘stocking glove’ distribution and distal weakness are the important features.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Not found in chronic mercury poisoning:", "options": [{"label": "A", "text": "Coarse tremor", "correct": false}, {"label": "B", "text": "Brownish spot on anterior lens capsule", "correct": false}, {"label": "C", "text": "Fine tremor", "correct": true}, {"label": "D", "text": "Inappropriate shyness and irritability", "correct": false}], "correct_answer": "C. Fine tremor", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Fine tremor Chronic mercury poisoning are:- Chronic exposure to elemental mercury yields a classic triad of gingivitis and salivation, tremors and neuropsychiatric changes. The symptoms are salivation, inflammation of gums and occasionally a blue line at their junction with teeth, sore mouth and throat, loosening of teeth, gastrointestinal disturbances, anaemia, anorexia, loss of weight and chronic inflammation of kidneys with progressive uraemia. Tremors (sometimes called Danbury tremors) occur first in the hands, then progress to the lips and tongue and finally involve arms and legs. The tremor is moderately coarse and is interspersed by jerky movements. The advanced condition is called hatter's shakes or glass-blowers shakes because they are common in persons working in glass-blowing and hat industries. The patient then becomes unable to dress. Write legibly or walk properly. The most severe form is known as concussion Mercurialis, in which no activity is possible. Mercurial erethism is seen in persons working with mercury in minor manufacturing firms. This term is used to refer to the psychological effects of mercury toxicity. These include anxiety, depression, shyness, timidity, irritability, loss of confidence, mental depression, delusions and hallucinations, suicidal melancholia, manic-depressive psychosis (mad hatter), emotional instability, loss of memory and insomnia. Mercurialentis is a peculiar eye change due to exposure to the vapour of mercury. It is due to a brownish deposit of mercury through the cornea on the anterior lens capsule. Slit-lamp examination demonstrates a malt-brown reflex from the anterior lens capsule. It is bilateral and has no effect on visual acuity. Renal damage results in membranous glomerulonephritis with hyaline casts and fatty casts in the urine. The kidney is the primary target.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Acrodynia or pink disease is associated with:", "options": [{"label": "A", "text": "Arsenic", "correct": false}, {"label": "B", "text": "Copper", "correct": false}, {"label": "C", "text": "Lead", "correct": false}, {"label": "D", "text": "Mercury", "correct": true}], "correct_answer": "D. Mercury", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mercury Acrodynia or pink disease (because it is Characterised by a generalized body rash) is thought to be an idiosyncratic hypersensitivity reaction particularly seen in children. This can be caused by chronic mercury exposure in any form. The onset is insidious with anorexia, insomnia, sweating, skin rash and photophobia. Hands and feet become puffy, pinkish, painful, and paraesthesia with peeling of the Teeth may be shed.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A blood sample was taken from a lead-poisoning patient. Punctate basophilia with anemia was detected. Punctate basophilia in chronic lead poisoning is observed in the cytoplasm of:", "options": [{"label": "A", "text": "Neutrophil", "correct": false}, {"label": "B", "text": "Basophil", "correct": false}, {"label": "C", "text": "Lymphocytes", "correct": false}, {"label": "D", "text": "RBCs", "correct": true}], "correct_answer": "D. RBCs", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>RBCs Punctate basophilia or basophilic stippling means the presence of many dark blue-coloured pinhead-sized spots in the cytoplasm of red blood cells, due to the toxic action of lead on porphyrin metabolism</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The least common feature of chronic lead poisoning:", "options": [{"label": "A", "text": "Colicky pain", "correct": false}, {"label": "B", "text": "Anaemia", "correct": false}, {"label": "C", "text": "Basophilic stippling", "correct": false}, {"label": "D", "text": "Lead palsy", "correct": true}], "correct_answer": "D. Lead palsy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lead palsy Lead Palsy:- It usually occurs late and is seen in less than 10% of cases. There may be tremors, numbness, hyperaesthesia, and cramps before the actual muscle weakness. It is more common in adults than in children, and men are particularly affected. The muscle groups affected are those most prone to fatigue. Usually, the extensor muscles of the wrist (wrist drop; radial nerve is affected) are affected, but the deltoid, biceps, anterior tibial (foot drop), and rarely muscles of the eye or intrinsic muscles of hand or foot are affected. Paralysis is associated with degeneration of the nerve and atrophy of the muscles. Recovery may be complete but is usually slow.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient came to the OPD with signs suggestive of chronic metal poisoning and a typical Burtonian line on gums. The Burtonian line is seen in chronic poisoning by:", "options": [{"label": "A", "text": "Arsenic", "correct": false}, {"label": "B", "text": "Copper", "correct": false}, {"label": "C", "text": "Lead", "correct": true}, {"label": "D", "text": "Zinc", "correct": false}], "correct_answer": "C. Lead", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lead Lead Line :- A stippled blue line, called the Burtonian line in case of chronic poisoning of lead, is seen on the gums in 50 to 70% of cases. It appears due to subepithelial deposit of granules at the junction with teeth, only near dirty or carious teeth, within a week of exposure, especially on the upper jaw. It is due to the formation of lead sulphide by the action of hydrogen sulphide formed by decomposed food in the mouth. A similar blue line may be seen in cases of poisoning by mercury, copper, bismuth, iron, and silver.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A middle-aged man presented with abdominal colic, ataxia, constipation, blue gums, and dehydration. Investigation showed punctate basophilia. The most likely cause is:", "options": [{"label": "A", "text": "Acute arsenic poisoning", "correct": false}, {"label": "B", "text": "Chronic arsenic poisoning", "correct": false}, {"label": "C", "text": "Chronic lead poisoning", "correct": true}, {"label": "D", "text": "Chronic mercury poisoning", "correct": false}], "correct_answer": "C. Chronic lead poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Chronic lead poisoning Punctate basophilia or basophilic stippling means the presence of many dark blue-coloured pinhead-sized spots in the cytoplasm of red blood cells, due to the toxic action of lead on porphyrin metabolism seen in case of chronic lead poisoning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Menstrual disorders and sterility in both sexes may be presenting features in which of the following chronic poisoning:", "options": [{"label": "A", "text": "Cadmium", "correct": false}, {"label": "B", "text": "Barium", "correct": false}, {"label": "C", "text": "Lead", "correct": true}, {"label": "D", "text": "Phosphorous", "correct": false}], "correct_answer": "C. Lead", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lead Menstrual derangements, such as amenorrhoea, dysmenorrhea, menorrhagia, sterility of both sexes and abortion are frequent. Abortion occurs in pregnant women between 3 to 6 months-are of all seen in case of chronic lead poisoning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A boy presented with signs of lead poisoning as he used to work at a petrol pump. Which of the following features is rare in adults compared to children in the case of Plumbism?", "options": [{"label": "A", "text": "Anaemia", "correct": false}, {"label": "B", "text": "Colic", "correct": false}, {"label": "C", "text": "Lead palsy", "correct": false}, {"label": "D", "text": "Encephalopathy", "correct": true}], "correct_answer": "D. Encephalopathy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Encephalopathy Lead encephalopathy, in some form, is said to be present in almost every case of Plumbism. It is common in children and often associated with tetraethyl lead. The symptoms are vomiting, headache, insomnia, visual disturbances, irritability, restlessness, delirium, hallucinations, convulsions, coma and death. Lead encephalopathy is usually irreversible and about 85% have permanent brain damage. Death occurs in about 25% of cases</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following chelating agents is recommended for acute Lead poisoning with signs of encephalopathy?", "options": [{"label": "A", "text": "Succimer", "correct": false}, {"label": "B", "text": "Penicillamine", "correct": false}, {"label": "C", "text": "Calcium EDTA", "correct": false}, {"label": "D", "text": "Dimercaprol + Calcium EDTA", "correct": true}], "correct_answer": "D. Dimercaprol + Calcium EDTA", "question_images": [], "explanation_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/"], "explanation": "<p><strong>Solution:</strong></p><p>Dimercaprol + Calcium EDTA Severe acute poisoning with encephalopathy: BAL 4 mg/kg immediately (in children). Repeat the same dose at 4 hourly intervals until blood lead levels fall below 40 mg/100 ml. Then reduce BAL to 12 mg/kg/day in 3 divided doses. CaNa2 EDTA 75 mg/kg/day i.v. infusion. Reduce EDT A to 50 mg/kg/day as the condition improves. The above regimen is continued until the patient is asymptomatic and can tolerate oral chelation with D-penicillamine 10mg/kg/day or DMSA, 10mg/kg/ dose t.i.d. for 20 days.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 26 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The consultant on duty directs the intern to get a bedside X-ray cervical spine of an RTA patient. However, the intern removes the cervical collar of the patient and shifts the patient to the X-ray room because the portable X-ray machine was not functioning properly. In case the patient succumbs to death because of the negligence of the intern, who also is held responsible?", "options": [{"label": "A", "text": "Intern", "correct": false}, {"label": "B", "text": "Consultant", "correct": true}, {"label": "C", "text": "X-ray technician", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "B. Consultant", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Consultant VICARIOUS LIABILITY (liability for the act of another): An employer is. responsible not only for his own negligence but also for the negligence of his employees, if such acts occur in the course of the employment and within its scope, by the principle of respondent superior (let the master answer). Conditions must be satisfied: There must be an employer-employee relationship, The employee's conduct must\" occur within the scope of his employment, and While on the job</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: A physician is responsible for the acts of the interns and residents carried out under his direct supervision and control. Option C: The X-ray technician is not related to the crime committed as he is not in charge of the patient.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "As a medical man, one is expected to know the legal aspect of your practice especially when one is handling a medicolegal case. Consider the following statements and pick the incorrect one", "options": [{"label": "A", "text": "In a case of drunkenness, he can be examined if instructed by a sub-inspector", "correct": false}, {"label": "B", "text": "In cases of rape, the victim should not be examined without written consent", "correct": false}, {"label": "C", "text": "For organ transplantation, the organs of the dead person, such as heart, kidney, liver, etc. should not be removed without the consent of the guardian or legal heirs", "correct": false}, {"label": "D", "text": "It is lawful to detain an adult patient in the hospital against his will since the chances of death is high in case he/she is discharged", "correct": true}], "correct_answer": "D. It is lawful to detain an adult patient in the hospital against his will since the chances of death is high in case he/she is discharged", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>It is lawful to detain an adult patient in the hospital against his will since the chances of death is high in case he/she is discharged It is unlawful to detain an adult patient in a hospital against his will. If a patient demands discharge against medical advice, this should be recorded and his signature obtained.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. In cases of drunkenness, the person should not be examined and blood, wine, or breath should not be collected without his written consent. But, if the person becomes unconscious or incapable of giving consent, examination and treatment can be carried out. The consent of the guardian or of relatives if available, should be taken. The person can be examined without consent if requested by the sub-inspector of the Option: B. In criminal cases, the victim cannot be examined without his/her consent. The Court also cannot force a person to get medically examined, against his will. In cases of rape, the victim should not be examined without written consent. In medicolegal cases of pregnancy, delivery, and abortion, the woman should not be examined without her consent Option: C. If any person has donated his body to be used for therapeutic or research purposes after his death, it is not binding on his 'spouse or next of kin. For organ transplantation, the organs of the dead person, such as the heart, kidney, liver, etc. should not be removed without the consent of the guardian or legal heirs. Precautions should be taken to preserve the anonymity of both the donor and recipient.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "One doctor conducted some fraudulent research on the MMR vaccine and falsely alleged that it was associated with autism, which caused a lot of hue and cry. The council labeled this as misconduct and decided to punish him. In case of professional misconduct, punishment is given by", "options": [{"label": "A", "text": "State Medical Council", "correct": true}, {"label": "B", "text": "Medical Council of India", "correct": false}, {"label": "C", "text": "Indian Medical Association", "correct": false}, {"label": "D", "text": "Courts of Law", "correct": false}], "correct_answer": "A. State Medical Council", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>State Medical Council This question wants to know your understanding of the functioning of different medical councils. Let’s look at the functioning of the Medical Council of India (now the National Medical Council) and the State Medical Council. Medical Council of India: Maintains a medical register of all the medical practitioners who are enrolled with the State Medical Council, so if a doctor is enrolled with any State Medical Council, his name will automatically enroll in the register maintained with the Medical Council of India; Prescribes standards of undergraduate and postgraduate medical education for the guidance of the universities; Prescribes standards of undergraduate and postgraduate medical education for the guidance of the universities; Gives opinion in cases of appeal against disciplinary action when a medical practitioner appeals to the central government against the decision of the State Medical Council, then the central government asks for the consultation of Medical Council of India; and Prescribes standards of professional conduct and etiquette and Code of Ethics, it also issues warning notices listing certain practices which are regarded as ‘serious professional misconduct’. So, overall, the Medical Council of India functions to maintain the standard of medical education and medical practice. State Medical Councils work on more ground level. They maintain a medical register and each and every medical practitioner has to enroll with a State Medical Council to practice; Have disciplinary control over the medical practitioners; and Can issue warning notice as Medical Council of India.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Medical Council of India- It is not directly involved in disciplinary control over the medical practitioners. However, they are involved in appeals when a medical practitioner appeals against disciplinary action of the State Medical Council. The medical practitioner appeals to the central government against the decision of the State Medical Council, central government then consults of Medical Council of India. Option: C. Indian Medical Association- Indian Medical Association is the only representative, national voluntary organization of Doctors of Modern Scientific System of Medicine, which looks after the interest of doctors as well as the well-being of the community at large. Option: D. Courts of Law- Here you have to be careful. The question asked is about ‘professional misconduct’ and not about ‘medical negligence’. It is ‘medical negligence’, whether civil or criminal, where courts of law play their roles and will punish him if found guilty. However, if courts of law think fit, they can direct the respective State Medical Council to take disciplinary action against the doctor. At last, it will be the State Medical Council, that will take corrective</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A lady was on the operation table for cholecystectomy. The surgical team was waiting for the anesthetist who was at a party. He attended the surgery and anesthetized the lady under the influence of alcohol. The surgery went uneventfully. Disciplinary action in professional misconduct of an anesthetist may be taken by:", "options": [{"label": "A", "text": "Surgeon", "correct": false}, {"label": "B", "text": "Medical Superintendent", "correct": false}, {"label": "C", "text": "Judicial Magistrate", "correct": false}, {"label": "D", "text": "State Medical Council", "correct": true}], "correct_answer": "D. State Medical Council", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>State Medical Council Serious Professional Misconduct = Infamous conduct in a professional respect is the conduct by a doctor which might reasonably be regarded as disgraceful or dishonorable; judged by professional men of good repute and competence. It involves abuse of professional position. Professional misconduct must not be confused with Professional negligence, which is the absence of reasonable care & skill or willful negligence of a medical practitioner in the treatment of patient, which causes bodily injury or death of the patient.</p>\n<p><strong>Random:</strong></p><p>Explanation For incorrect options:- Option: A. surgeon is not authorized to take disciplinary action. Option: B . Medical superintendent can take disciplinary action for being under the influence on duty but not for professional misconduct. Option: C. As a case of alleged Professional negligence against a doctor comes up in a court of law, it shall be decided by a Judicial Magistrate.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A relative filed a criminal case against a medical practitioner when the patient died under his care. The punishment awarded to a doctor if found guilty of professional criminal negligence is:", "options": [{"label": "A", "text": "Imprisonment for 2 years", "correct": false}, {"label": "B", "text": "Fine", "correct": false}, {"label": "C", "text": "Imprisonment for 7 years", "correct": false}, {"label": "D", "text": "2 years imprisonment and fine", "correct": true}], "correct_answer": "D. 2 years imprisonment and fine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>2 years imprisonment and fine Professional negligence = Malpractice is of 2 types- Civil Negligence and Criminal Negligence. A doctor held guilty of Criminal Negligence can be charged under Sec. 304A IPC for ‘Causing death by a rash & negligent act’. The punishment under this section is up to 2 years with or without a In addition, the doctor can also be tried for Civil negligence in a Civil court where he might be liable to pay damages to the patient.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: This option suggests only imprisonment of 2 years and no fine. Hence it is not the correct answer. Option B: This option suggests only acceptable and no imprisonment. Hence it is not the correct answer. Option C: It suggests imprisonment for 7 years while the correct answer is only for two years including a fine</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A child was given penicillin for a sore throat. He succumbed to an an aphylactic reaction. Death of a patient due to an unintentional act by a doctor, staff or hospital is:", "options": [{"label": "A", "text": "Therapeutic misadventure", "correct": true}, {"label": "B", "text": "Vicarious liability", "correct": false}, {"label": "C", "text": "Therapeutic privilege", "correct": false}, {"label": "D", "text": "Diminished liability", "correct": false}], "correct_answer": "A. Therapeutic misadventure", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Therapeutic misadventure A therapeutic misadventure is a mischance or accident or disaster. Therapeutic misadventure is a case in which an individual has been injured or died due to some unintentional act by a doctor or agent of the doctor or hospital.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Option:- Option: B. Vicarious liability is a liability for acts of others i.e. an employer is responsible not only for his own negligence but also for the negligence of his employment by the principle of respondent superior (let the master answer), provided there : Must be an employer-employee relationship, While on the job, Employee conduct within the job of employment. Option: C. Therapeutic privilege is an exception to the rule of ‘full disclosure’ i.e. the doctor can use his discretion as to the facts that he discloses or not telling the patient about the risks involved in treatment or about the diagnosis, e.g. in cases where the patient is fearful, emotionally disturbed, psychotic or psycho-neurotic. The doctor should carefully note his decision in the patient’s records mentioning the reasons. Option D. Diminished responsibility is a defense that states that someone is not mentally well enough to be totally responsible for their crime.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Being a registered medical practitioner, every doctor has rights and duties. Which one of the following is not a right & privilege of a registered medical practitioner?", "options": [{"label": "A", "text": "Right to choose a patient", "correct": false}, {"label": "B", "text": "Right to add a title to the name", "correct": false}, {"label": "C", "text": "Right to the recovery of fees", "correct": false}, {"label": "D", "text": "Right to own an organ for transplantation", "correct": true}], "correct_answer": "D. Right to own an organ for transplantation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Right to own an organ for transplantation There is no right or privilege to own an organ of another person for training purposes.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A, B & C: Rights & Privileges of a Doctor:- O ption A: Right to choose a patient, Right to practice medicine, Right to dispense medicine, Right to possess and supply dangerous drugs to his patients Option B: Right to add title, Option C : Right to the recovery of fees, Right to issue a medical certificate, Right to give evidence as an expert, Right for appointment in public/govt. hospital, Exemption from serving as a juror at an inquest.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "After an investigation, the state medical council sentenced a doctor's to professional death. “Professional Death sentence” is:", "options": [{"label": "A", "text": "Erasure of name from the register of a medical practitioner.", "correct": true}, {"label": "B", "text": "Life imprisonment.", "correct": false}, {"label": "C", "text": "Rigorous imprisonment with fine.", "correct": false}, {"label": "D", "text": "Judicial execution by hanging", "correct": false}], "correct_answer": "A. Erasure of name from the register of a medical practitioner.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Erasure of name from the register of a medical practitioner. MCI & State Medical Council Medical Jurisprudence Deals with legal aspects of medicine e.g legal rights, privileges, duties, and obligations of an RMP Medical ethics: Code containing moral principles for information & guidance for RMP in dealing with: each other, patients & State. Medical etiquette: Code of conduct governing the relationship of a doctor with his professional colleagues. Medical Council of India: Latest development: MCI to be replaced by National Medical Commission Schedules of MCI: Recognized medical qualifications granted by: 1st Schedule –Universities or Medical institutions in India. 2nd Schedule - Medical institutions outside India. 3rd Schedule – Part I - Medical institutions in India not included in the First Schedule. Part II - Medical institutions outside India not included in the Second Schedule. Functions of MCI Maintenance of a Medical Register Medical Education: Recognition of foreign medical qualifications Appeal against disciplinary action Warning notice: Functions of State Medical Council Maintenance of the medical register Origin: Oldest code – Hippocratic Oath Followed by the World Medical Association as the Declaration of Geneva. Accepted by MCI as Code of Ethics. Declaration of Geneva Use of Red Cross Emblem: Right only for members of medical service of any army. Use by others including doctors/ paramedical staff is prohibited. Punishable –Fine up to Rs.500/ & Forfeiture of property on which it has been used. Disciplinary control: Penal erasure, professional death sentence Penal erasure refers to the removal of a medical practitioner’s name from the Medical Register temporarily or permanently as a penalty. Done when a doctor is guilty of Professional misconduct (infamous conduct). Issue warning notice similar to MCI.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C & D: they may sound similar but a professional death sentence is different from imprisonment sentences issued by the courts.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Dr. Amjad, a fresh MBBS pass-out, is working as a Duty Doctor at a local hospital near his hometown. One of his relatives covered in blood was brought dead to the hospital. The relatives who came after a few minutes were demanding a Death Certificate. How should Dr. Amjad manage the situation: File an MLC. Inform the police. Do not hand over the body to the relatives. Do not issue the Death certificate to the relatives. Select the correct answer from given below code:", "options": [{"label": "A", "text": "A, B, C, D", "correct": true}, {"label": "B", "text": "A, B, D", "correct": false}, {"label": "C", "text": "A, B , C", "correct": false}, {"label": "D", "text": "A, B", "correct": false}], "correct_answer": "A. A, B, C, D", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A, B, C, D If a person is brought dead to the hospital: File an MLC. Inform the police. Do not hand over the body to the relatives. Fill out the death certificate form without giving the cause of death but do not issue it to the relatives. Do not issue a death certificate or do not release the body to the relatives if: injured and brought dead; crime was regd by the police; cause of death is unknown; the police have already been informed.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A suspected case of infanticide was referred to the District hospital from a rural PHC. The case reached the DH very late at night. Which of the following is applicable in this situation:", "options": [{"label": "A", "text": "The CMO at the DH has to register a fresh MLC again, even if a MLC is registered by the PHC doctor.", "correct": false}, {"label": "B", "text": "MLC cases should only be examined in day light.", "correct": false}, {"label": "C", "text": "The CMO should seek expert opinion if he is unable to finalise the report.", "correct": true}, {"label": "D", "text": "Since it is an infanticide, no need of informing the police.", "correct": false}], "correct_answer": "C. The CMO should seek expert opinion if he is unable to finalise the report.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The CMO should seek expert opinion if he is unable to finalise the report. The doctor can seek expert opinion in order to finalize the report.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. If a case is brought and has been registered MLC by some other hospital, then there is no need for a fresh medico-legal Option: B. MLCs should be examined without any delay at any time day or night. Option: D. Infanticide is a medicolegal case and the Police should be informed.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "In 1890, there lived a person who had hypersexuality disorder, raped almost 60 women in his lifetime but was never caught. In his 61st rape attempt, he was caught and taken to court. The first punishment ordered by the court was sterilization. What is the kind of sterilization done in this man?", "options": [{"label": "A", "text": "Voluntary sterilization", "correct": false}, {"label": "B", "text": "Compulsory sterilization", "correct": true}, {"label": "C", "text": "Therapeutic sterilization", "correct": false}, {"label": "D", "text": "Eugenic sterilization", "correct": false}], "correct_answer": "B. Compulsory sterilization", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Compulsory sterilization COMPULSORY STERILIZATION: It is performed on a person compulsorily, by an order of the State. It may be carried out on mental defectives and others from a strictly eugenic point of view or as a punishment for sexual criminals. It is not done in India.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C, & D. VOLUNTARY STERILIZATION: It is performed on married persons with the consent of both the husband and wife. It is performed for Therapeutic, Eugenic, and Contraceptive purposes. Therapeutic: This is performed to prevent danger to the health or life of the woman due to a future pregnancy. Eugenic: Sterilization performed to prevent the conception of children who are likely to be physically or mentally defective. The object is to improve the race by preventing the transmission of disease and heritable defects. Contraceptive: It is performed to limit the size of the family, i.e., for family planning</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The husband has epispadias, therefore the doctor suggests artificial insemination to the couple. Pick the wrong statement regarding the same.", "options": [{"label": "A", "text": "AIHD is pooled donor semen consisting of husband and donor semen", "correct": false}, {"label": "B", "text": "Consent of the husband is sufficient for this procedure", "correct": true}, {"label": "C", "text": "Frozen semen for AID is done by the addition of glycerol, slow cooling, rapid freezing, and storage at minus 196 degrees", "correct": false}, {"label": "D", "text": "The identity of the donor should not be revealed", "correct": false}], "correct_answer": "B. Consent of the husband is sufficient for this procedure", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Consent of the husband is sufficient for this procedure Consent of husband and wife is required for this procedure</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Types of artificial insemination If the semen of the woman's husband is used, it is known as 'artificial insemination homologous' or \"artificial insemination husband\" (A.I.H). If the semen of some person other than the husband is used, it is known as an \"artificial insemination donor\" (A.I.D). 'Pooled' donor semen is composed of donor semen to which semen from the husband has been added (A.l.H.D.). Option: C. Biological Aspects: Semen is obtained by masturbation and one ml. is deposited by means of a syringe in or near the cervix. The timing of insemination is important as the lifespan of the spermatozoa in the female reproductive tract is short. The ovum can survive in a fertilized form only for about 24 hours, and probably only for 8 to 12 hours after it leaves the ovary. The time of maximum fertility coincides with ovulation. The ovum can survive in a fertilized form for 8 to 12 hours after it leaves the ovary. The usual time taken by sperm to travel from the vagina to the tubes is 6 to 24 hours. The power of sperm to fertilize is usually retained for about 48 hours. Because of the problem of timing, insemination on several successive days in the month increases the chances of pregnancy. The use of frozen semen for AI. D. is becoming increasingly common. This is done by the addition of glycerol, slow cooling, rapid freezing, and storage below minus 79 degree C. Option: B & D. Indications: When the husband is impotent. When the husband is unable to deposit the semen in the vagina due to hypospadias, epispadias, etc. When the husband is sterile. When there is Rh incompatibility between the husband and wife. When the husband is suffering from a hereditary disease. Precautions: Certain recommendations have been made when a donor is used. They are : The consent of the donor and his wife is essential. The identity of the donor must remain secret. The donor should not know to whom the semen is donated and the result of insemination. The donor must be mentally and physically healthy and should not be suffering from any hereditary or familial disease. He should be screened with all available tests including chromosomal studies for possible genetic defects. The donor must not be a relative of either spouse, he should have had children of his own. The race and characteristics of the donor should resemble those of the husband of the woman as closely as possible. The donor should be of the same blood group as that of the husband There should not be any Rh incompatibility between the donor and recipient. The physician should have permission to use his own best judgement in selecting the donor. The couple should be psychologically fit and emotionally stable. The woman to be inseminated and her husband must give consent in writing that an unknown donor should be used. A witness must be present when insemination is done. It is usually wise to use \"pooled\" semen. When the husband's semen is mixed with that of a donor, there is the technical possibility that the husband may, in fact, be the father of the child. The physician who administers artificial insemination should avoid delivering the child. This will avoid the necessity of either falsifying the birth records or disclosing the true paternity in those records. Usually, a single donor's semen is not used to produce more than ten children.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The husband is impotent. The wife and husband mutually agree to have a child by artificial insemination. Choose the correct statement:", "options": [{"label": "A", "text": "The wife cannot file a divorce because, they have had a child", "correct": false}, {"label": "B", "text": "The wife can still divorce her husband", "correct": true}, {"label": "C", "text": "The wife can take a share in the husband's property but can't divorce him legally", "correct": false}, {"label": "D", "text": "Both a and c", "correct": false}], "correct_answer": "B. The wife can still divorce her husband", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The wife can still divorce her husband When A.I. was done due to the impotence of the husband, the wife may ask for nullity or divorce, even if a child was born out of A.I.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C, & D: Nullity of Marriage and Divorce Mere artificial insemination (A.I) is not a ground for nullity of marriage or divorce, because sterility is not a ground for it. However, if A. I. is due to impotence, it is a ground for divorce. The consent of the husband has no bearing on this. If A.l. is done without the consent of the husband, he can sue his wife for a divorce and the doctor for damages.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A couple is married for 5 years now but then, but the husband is unable to have sexual intercourse with his wife. Frustrated with his wife for her inability to have sexual intercourse, he has an extramarital affair with two other women and is able to satisfy his desire for sexual intercourse with those two women. This is:", "options": [{"label": "A", "text": "Quoad hoc", "correct": true}, {"label": "B", "text": "Impotency", "correct": false}, {"label": "C", "text": "Sterility", "correct": false}, {"label": "D", "text": "Vaginismus", "correct": false}], "correct_answer": "A. Quoad hoc", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Quoad hoc Quoad Hoc is where someone is not able to have sex with a particular woman</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B & C. Quoad Hoc is when someone is not able to have sex with a particular woman . Option: D. Vaginismus is a spasmodic contraction of the vagina due to hyperaesthesia. It is a classical example of a psychosomatic illness.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A female has excessive sexual desire, but her husband is not as much interested as her. She is considered:", "options": [{"label": "A", "text": "Nymphomaniac", "correct": true}, {"label": "B", "text": "Satyriasis", "correct": false}, {"label": "C", "text": "Both a and b", "correct": false}, {"label": "D", "text": "Sexual dysfunction", "correct": false}], "correct_answer": "A. Nymphomaniac", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Nymphomaniac Nymphomania:-excessive sexual desire in a female</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B & C. Satyriasis :- excessive sexual desire in a male which in turn cannot be satisfied by a normal woman usually has a wife Option: D. Sexual dysfunction is impairment either in the desire for sexual gratification or in the ability to achieve it.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person came to a psychiatric office with complaints of impotency as the attending physician did not find any physical cause. With reference to the psychic cause of impotence, choose the wrong statement:", "options": [{"label": "A", "text": "Impotence in males is passive leading to a non-erection", "correct": false}, {"label": "B", "text": "Impotence in females is active leading to vaginismus", "correct": false}, {"label": "C", "text": "First-night impotence is commonly seen in the bride", "correct": true}, {"label": "D", "text": "Honeymoon impotence is seen in the bridegroom", "correct": false}], "correct_answer": "C. First-night impotence is commonly seen in the bride", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>First-night impotence is commonly seen in the bride Fear of impotence or fear of inability to complete the act (first-night impotence/honeymoon impotence in the bridegroom) are common causes of temporary impotence but usually, they are soon overcome.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, & B. Psychic factors may lead to impotence commonly in males. In males, the impotence is passive leading to non-erection, but in females it is of an active nature, leading to vaginismus. Vaginismus is a spasmodic contraction of the vagina due to hyperaesthesia. It is a classical example of a psychosomatic illness. Anatomically, it may affect the perineal muscles exclusively or may be felt as a varying constriction of the levator ani, right up to the vaginal Fornices. Any attempt at intercourse will cause painful reflex spasm of the levator ani, perineal muscles, adductor muscles of thighs and erector spinae muscles Option: D. Emotional disturbances are a common cause of temporary impotence. Fear of impotence or fear of inability to complete the act (first-night impotence/honeymoon impotence in the bridegroom) is common cause of temporary impotence but usually, they are soon overcome. Disgust of the sexual act or dislike of the partner may cause temporary or permanent impotence. Anxiety, guilt sense, timidity, depression, excessive passion, and sexual overindulgence produce temporary impotence. Quoad hoc (as far as this) is an individual who may be impotent with one particular woman but not with others. Nocturnal penile tumescence has revealed that a majority of cases of impotence have organic causes. Vasculogenic impotence is one of the most frequent causes of erectile failure. Vasculogenic impotence may be due to poor arterial inflow into the penis due to arteriosclerotic narrowing of the arteries supplying the penis</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A foreign medical graduate of Indian nationality completed his mandatory internship in India after clearing the screening test. Who shall give him the recognition to practice in India?", "options": [{"label": "A", "text": "National Medical Commission", "correct": true}, {"label": "B", "text": "State Medical Council", "correct": false}, {"label": "C", "text": "NBE", "correct": false}, {"label": "D", "text": "Both NMC and SMC", "correct": false}], "correct_answer": "A. National Medical Commission", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>National Medical Commission Recognition of Foreign Medical Qualifications : If an Indian national obtains a foreign qualification that is not included in part II of the Third Schedule, he can apply to the Central Government. The candidate is required to provide full information with regard to the course of study, syllabus, duration of the course, etc. This is forwarded to I.M.C., which has the authority to enter into negotiations with any of the Medical Councils of the foreign countries and can recognize such foreign qualifications on a reciprocal basis. The Central Government may, by notification in the Official Gazette, amend part II of the Third Schedule so as to include such qualification therein.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C , & D. Recognition of foreign medicals is not included in the duties of the State Medical Council or NBE. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A reproductive-aged woman presents with severe stomach pain to the emergency room at 1 AM. The doctor on duty who was intoxicated with alcohol takes her up for surgery assuming the cause of stomach pain to be appendicitis and operated on her. The doctor here shows", "options": [{"label": "A", "text": "Infamous conduct", "correct": true}, {"label": "B", "text": "Professional secrecy", "correct": false}, {"label": "C", "text": "Novus actus Interveniens", "correct": false}, {"label": "D", "text": "Res is a loquitar", "correct": false}], "correct_answer": "A. Infamous conduct", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Infamous conduct Serious Professional Misconduct: (Infamous conduct in professional respect): It is any conduct of the doctor which might reasonably be regarded as disgraceful or dishonorable. The conduct of the doctor is judged by professional men of good repute and competence. it involves an abuse of professional position. The significant offenses may be described as \"the 6 A's\". Adultery arising out of a professional Advertising Abortion (unlawful). Association with unqualified persons in professional matters. Addiction Alcohol Rights and Privileges of Registered Medical Practitioners: Right to practice medicine. Right, to choose a patient. Right to dispense medicines. Right to possess and supply dangerous drugs to his patients. Right to add title, descriptions, etc., to the name. Right to the recovery of fees. Right for appointment to public and local hospitals. Right to issue medical certificates. Right to give evidence as an expert.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. PROFESSIONAL SECRECY (confidentiality): It is an implied contract term between the doctor and his patient. The relationship between doctor and patient requires utmost trust, confidence, fidelity, and honesty. The doctor is obliged to keep secret, all that he comes to know concerning the patient in the course of his professional work. Option: C. NOVUS ACTUS INTERVENTIONS: A person is responsible not only for his actions but also for the logical consequences of those actions. Option: D. THE DOCTRINE OF RES IPSA LOQUITUR: Ordinarily, the professional negligence of a physician must be proved in Court by the expert evidence of another physician. The patient need not prove negligence in cases where the rule of res ipsa loquitur applies, which means \"the thing or fact speaks for itself\". The patient has to merely state what according to him was the act of negligence.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A doctor is fined Rs. 1 lakh due to civil negligence and the case has been settled. The patient party, not being satisfied with the compensation, re-appeals to the court after 1 year. Which of the following best describes such a case?", "options": [{"label": "A", "text": "Law of limitation", "correct": false}, {"label": "B", "text": "Res Judicata", "correct": true}, {"label": "C", "text": "Therapeutic misadventure", "correct": false}, {"label": "D", "text": "Resipsa Loquitor", "correct": false}], "correct_answer": "B. Res Judicata", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Res Judicata Res judicata (S. 300, Cr.P.C.). If a question of negligence against a doctor has already been decided by a Court in a dispute between the doctor and his patient. The patient will not be allowed to contest the same question in another proceeding between himself and the doctor on the same set of facts.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Law of limitation A suit for damages for negligence against the doctor should be filed within two years from the date of alleged negligence. A suit was filed after. Two years will be dismissed as being beyond the period of limitation. Where the breach of duty to provide care as per a particular contract between a patient and a doctor is committed, legal action can be initiated up to three years from the date of alleged negligence. Option: C. Therapeutic misadventure is a mischance or accident or disaster. Misadventure is of three types: Therapeutic (when treatment is being given). Diagnostic (where diagnosis only is the objective at the time). Experimental (where the patient has agreed to serve as a subject in an experimental study). Option: D. THE DOCTRINE OF RES IPSA LOQUITUR: Ordinarily, the professional negligence of a physician must be proved in Court by the expert evidence of another physician. The patient need not prove negligence in a case where the rule of res ipsa loquitur applies, which means \"the thing or fact speaks for itself\". The patient has to merely state what according to him the act of negligence was.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Hospital staff and his two other companions were arrested for illegal organ trafficking. The Transplantation of Human Organ act was passed in:", "options": [{"label": "A", "text": "1993", "correct": false}, {"label": "B", "text": "1994", "correct": true}, {"label": "C", "text": "1995", "correct": false}, {"label": "D", "text": "1996", "correct": false}], "correct_answer": "B. 1994", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1994 Transplantation of the human organ act was passed in 1994. There are three main aspects of the Act: It aims at putting a stop to living unrelated transplants. In the case of a live-related transplant, it defines that the donor and recipient are genetically related, with an exception if the transplant is done with prior approval of the Authorisation Committee on an application jointly made by the donor and recipient. It accepts the brain stem death criterion. Bone marrow transplant is outside the purview of the Act. The organs that can be donated after death are kidneys, heart, liver, lungs, pancreas, eyes, eardrums, and ear bones.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "When a homicide case comes to a doctor, he has to inform the police. This comes under which section?", "options": [{"label": "A", "text": "39 Crpc", "correct": true}, {"label": "B", "text": "27 Crpc", "correct": false}, {"label": "C", "text": "174 Crpc", "correct": false}, {"label": "D", "text": "176 Crpc", "correct": false}], "correct_answer": "A. 39 Crpc", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>39 Crpc If a private practitioner is convinced it’s a homicidal case, he is bound under S. 39, Cr. P.C. to inform the police officer or Magistrate.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: C & D. 174 CrPC and 176 CrPC are related to Police Inquest and Magistrate Inquest. Hence they cannot be the right options. Option: B. CrPC 27 is not related to informing police about a homicide case. Hence it is also not the correct option.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Prohibition of participation in torture by a doctor comes under the:", "options": [{"label": "A", "text": "Declaration of Tokyo", "correct": true}, {"label": "B", "text": "Declaration of Helsinki", "correct": false}, {"label": "C", "text": "Declaration of Oslo", "correct": false}, {"label": "D", "text": "Declaration of Geneva", "correct": false}], "correct_answer": "A. Declaration of Tokyo", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Declaration of Tokyo DECLARATION OF TOKYO The doctor shall not countenance, condone or participate in the practice of torture(physical or mental suffering) or other forms of cruel, inhuman, or degrading procedure, whatever the offense of prisoners or detainees may be, and whatever be the victim's motives or beliefs, and in all situations, including armed conflict and civil strife. The doctor shall not provide any premises, instruments, substances, or knowledge to facilitate the practice of torture or other forms of cruel, inhuman, or degrading treatment or to diminish the ability of the victim to resist such treatment. The doctor shall not be present during any procedure during which torture or other forms of cruel treatment is used or threatened. A doctor must have complete clinical independence in deciding upon the care of a patient. If a prisoner refuses nourishment and is capable of forming a rational judgment about the consequences, he should not be fed artificially. The doctor shall in all circumstances be bound to alleviate the distress of his fellow men, and no motive shall prevail against this higher purpose.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B: The Declaration of Helsinki(1975) is concerning human experimentation and clinical trials. Option C: The Declaration of Oslo (1970 & 1983) is concerning therapeutic abortion. Option D: The Declaration of Geneva- The general principles mentioned in the Hippocratic Oath have been brought up-to-date by the World Medical Association. The modernized version of the Hippocratic Oath is the Declaration of Geneva.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Repeated advertisements in the newspaper by a medical practitioner are an example of:", "options": [{"label": "A", "text": "Infamous conduct", "correct": true}, {"label": "B", "text": "Civil negligence", "correct": false}, {"label": "C", "text": "Criminal Negligence", "correct": false}, {"label": "D", "text": "Privileged communication", "correct": false}], "correct_answer": "A. Infamous conduct", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Infamous conduct The critical offenses may be described as\"the 6 A's\". Adultery arising out of a professional Advertising Abortion (unlawful). Association with unqualified persons in professional matters. Addiction Alcohol Printing of a self-photograph or any such material of publicity on the letterhead or on the sign board of the consulting room or any such clinical establishment shall be regarded as an act of self-advertisement and unethical conduct on the part of the physician. However, the printing of sketches, diagrams, and pictures of the system shall not be treated as unethical.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C, & D. Advertising is not related to any type of negligence or communication privileges. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The doctor conducted a knee transplant, however, the patient succumbed during the recovery. On further investigation, it was revealed that it was the wrong side knee transplantation. The doctor is punishable under section-", "options": [{"label": "A", "text": "S. 304 A IPC", "correct": true}, {"label": "B", "text": "S. 302 IPC", "correct": false}, {"label": "C", "text": "S.305-A IPC", "correct": false}, {"label": "D", "text": "S.305 IPC", "correct": false}], "correct_answer": "A. S. 304 A IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>S. 304 A IPC Section 304 –A IPC Causing death by negligence: whosoever causes the death of any person, by doing any rash or negligent act not amounting to culpable homicide shall be punished with imprisonment for a term which may extend to 2 years or with a fine, or with both The doctor doing surgery on the wrong side of the patient is an example of gross inattention and recklessness shown by the doctor and is thus an example of criminal negligence Criminal negligence is punishable under S.304 AIPC</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. 302, I.P.C.: Punishment for murder: Death, or imprisonment for life, and also fine. Option: C & D. 305, I.P.C.: Abetment of the suicide of child or insane person (ten years imprisonment).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A Soldier was posted to the Siachen glacier camp region for training. He was exposed to temperatures less than -2.5 degree Celsius. Skin changes are noticed as shown in the Image given below. What is the diagnosis", "options": [{"label": "A", "text": "Trench foot", "correct": false}, {"label": "B", "text": "Frostbite", "correct": true}, {"label": "C", "text": "Immersion foot", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "B. Frostbite", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893585409-QTDF061001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Frostbite Explanation For Incorrect Options:- Option: A & C. Trench foot and immersion feet result from prolonged exposure to severe cold (5 to 8 degrees Celsius) and dampness, seen in persons exposed to prolonged immersion or exposure at sea. The extremities are affected by those conditions. Blister formation with ulceration and localised dry gangrene occurs.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & C. Trench foot and immersion feet result from prolonged exposure to severe cold (5 to 8 degrees Celsius) and dampness, seen in persons exposed to prolonged immersion or exposure at sea. The extremities are affected by those conditions. Blister formation with ulceration and localised dry gangrene occurs.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A Himalayan climber got stuck in an avalanche and succumbed. His body was later sent for post-mortem. The forensic expert conducting the post-mortem expects a characteristic finding in the dead climber. What is that?", "options": [{"label": "A", "text": "Pink or brown-pink areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips", "correct": true}, {"label": "B", "text": "Pale areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips", "correct": false}, {"label": "C", "text": "Black or brown-black areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips", "correct": false}, {"label": "D", "text": "Yellow areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips", "correct": false}], "correct_answer": "A. Pink or brown-pink areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pink or brown-pink areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips POSTMORTEM APPEARANCES IN PEOPLE WHO DIED OF EXTREME COLD TEMPERATURE: EXTERNAL FINDINGS Pink or brown-pink areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips, are characteristic. There may be pink patches on the cheeks, chin and nose. The extremities may be cyanosed. Oedema may be seen in the feet and lower legs. PM's lividity is bright INTERNAL FINDINGS The appearances are not characteristic. The subcutaneous tissues are relatively avascular. Ice crystals can be found in blood vessels, the heart and interstitial tissue spaces. The blood is often bright red due to oxygen retention by haemoglobin at low temperatures. The stomach mucosa is studded with numerous brown-black acute erosions, ulcerations and haemorrhages similar to those seen in many types of pre-death stress. A variable degree of fat necrosis of the pancreas is seen in about 50% of cases. Areas of stiff, yellow fat necrosis are seen in the pancreas and adjacent areas of omentum and mesentery. Pulmonary oedema and microinfarcts in many organs are common. Perivascular haemorrhages in the brain and small infarcts in the heart 3. are Internal organs are congested.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 75-year-old man is found in a cupboard with no clothing on him. There's a haphazard scene in the house. The sofa set is dragged into the dining area. All the contents of the drawers are found on the floor. What do you suspect in such a case?", "options": [{"label": "A", "text": "Hide-and-die syndrome", "correct": false}, {"label": "B", "text": "Terminal burrowing syndrome", "correct": false}, {"label": "C", "text": "Paradoxical undressing", "correct": false}, {"label": "D", "text": "all three A and B, and C", "correct": true}], "correct_answer": "D. all three A and B, and C", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>all three A and B, and C Option: A, B. THE HIDE-AND-DIE SYNDROME /Terminal burrowing behaviour In some cases of hypothermic death, the disoriented, dying hypothermia victim, who, while attempting to protect himself from the cold, may hide in corners, in cupboards or under piles of furniture or household goods. More commonly, a naked or partly clothed old person is found amid a scene of utter confusion with furniture pulled over and drawers and cupboards emptied, but the disturbance is at a low level, and the tops of tables, etc., are not disturbed. This may lead to suspicion of homicide and robbery. Outdoors, he may attempt to burrow into the snow, bush, or other constituents of the environment. The signs of hypothermia are usually found. The problem arises as to whether the victim became hypothermic first, which leads to mental confusion causing strange behaviour, or whether, due to some mental aberration, the person began behaving abnormally. Option: C. RECIPROCAL OR PARADOXICAL UNDRESSING: This abnormal condition is seen in accidental hypothermia, particularly in old persons. In this, people take off some or all of their clothing. The cause of the condition is not known. It may be due to prolonged exposure to severe cold-producing paralysis of the thermal regulatory mechanism. This results in the failure of vasoconstriction of arterioles of the skin, which results in a blood flow from the body's core, thus giving an exaggerated sensation of warmth. Terminal hallucinations occur. Because of the significant discomfort, the person may undress. In such cases, there may be suspicion of a sexual</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A soldier posted in the Himalayan region came to you with frostbite. Frostbite occurs when continuous exposure to temp. range of:", "options": [{"label": "A", "text": "Below –10°C", "correct": false}, {"label": "B", "text": "Below –2.5°C", "correct": true}, {"label": "C", "text": "2 – 4°C", "correct": false}, {"label": "D", "text": "5 – 10°C", "correct": false}], "correct_answer": "B. Below –2.5°C", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Below –2.5°C Frostbite is infarction of the peripheral digits with oedema, redness and later necrosis of the tissue beyond a line of inflammatory demarcation. It may affect only the skin or may extend deeply. It occurs due to exposure to greater extremes of cold (-2.5°C), develops more rapidly and in addition to the extremities, it frequently affects other parts, e.g., the nose, ears and face. In frostbite, necrosis with blister formation and gangrene occur. Skin becomes hard and black in about two</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A dead body was recovered naked under the pile of books and newspapers on a cold morning. Hide-and-die syndrome is reported with:", "options": [{"label": "A", "text": "Hyperthermia", "correct": false}, {"label": "B", "text": "Hypothermia", "correct": true}, {"label": "C", "text": "Hypocalcaemia", "correct": false}, {"label": "D", "text": "Hypercalcemia", "correct": false}], "correct_answer": "B. Hypothermia", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hypothermia THE HIDE-AND-DIE SYNDROME (Terminal burrowing behaviour): In some cases of hypothermia death, the disoriented, dying hypothermia victim, who, while attempting to protect himself from the cold, may hide in corners, in cupboards or under piles of furniture or household goods. More commonly, a naked or partly clothed old person is found amid a scene of utter confusion with furniture pulled over and drawers and cupboards emptied, but the disturbance is at a low level, and the tops of tables, etc., are not disturbed. This may lead to suspicion of homicide and robbery. Outdoors, he may attempt to burrow into the snow, bush, or other constituents of the environment. The signs of hypothermia are usually found. The problem arises as to whether the victim became hypothermic first, which leads to mental confusion causing strange behaviour, or whether the person began behaving abnormally due to some mental aberration.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A miner is involved in his routine work. As he was mining, he started to sweat profusely. He complains of vomiting, dizziness, tinnitus and muscle cramps in his calf muscles. Which of the following is not the diagnosis?", "options": [{"label": "A", "text": "Heat cramps", "correct": false}, {"label": "B", "text": "Stokers cramps", "correct": false}, {"label": "C", "text": "Heat prostration", "correct": true}, {"label": "D", "text": "Miners cramps", "correct": false}], "correct_answer": "C. Heat prostration", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Heat prostration Heat prostration is a condition of collapse without an increase in body temperature, which follows exposure to excessive heat.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B, D. HEAT CRAMPS: (miner's cramps, stoker's cramps or fireman's cramps): They are caused by rapid dehydration of the body through the loss of water and salt in the sweat. It is seen in workers in high temperatures when sweating has been profuse. The onset is usually sudden. Severe and painful paroxysmal cramps affecting the arms, legs and abdomen muscles occur. The face is flushed, the pupils dilated, and the patient complains of dizziness, tinnitus, headache and vomiting. Intravenous injection of saline gives rapid relief.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An athlete is practising a hurdle race on a sunny day for an upcoming national tournament. His rectal temperature is more than 41 degrees Celsius. He falls and gets an episode of convulsions. This is", "options": [{"label": "A", "text": "Sunstroke", "correct": true}, {"label": "B", "text": "Heat syncope", "correct": false}, {"label": "C", "text": "Heat collapse", "correct": false}, {"label": "D", "text": "Heat exhaustion", "correct": false}], "correct_answer": "A. Sunstroke", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sunstroke Heat stroke is characterised by rectal temperature greater than 41°C., and neurological disturbances, such as psychosis, delirium, stupor, coma and convulsions. The term thermic fever or \"sunstroke\" is used when there has been direct exposure to the sun. Predisposing factors: High temperature, increased humidity, minor infections, muscular activity and lack of acclimatisation are the principal factors in the initiation. Where there is 100 per cent humidity, a temperature of 32°C in the environment may lead to heat stroke. Other factors are old age, pre-existing disease, alcoholism, use of significant tranquillisers, obesity, lack of air movement and unsuitable clothing. Failure of cutaneous blood flow and sweating, which control body temperature, leads to a breakdown of the heat-regulating centre of the hypothalamus.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Lightning strikes a house. The person living in that house notices the marks on his body, is shown below. Choose the incorrect statement.", "options": [{"label": "A", "text": "This is called Lichtenberg's flowers", "correct": false}, {"label": "B", "text": "These markings have a general pattern resembling the branches of a tree.", "correct": false}, {"label": "C", "text": "This fern-like pattern of erythema in the skin is usually found over the shoulders or the flanks.", "correct": false}, {"label": "D", "text": "It appears after 24 hours of the accident", "correct": true}], "correct_answer": "D. It appears after 24 hours of the accident", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893585468-QTDF061008IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>It appears after 24 hours of the accident Arborescent /Filigree Burns/Lichtenberg's flowers They are superficial, thin, irregular and tortuous markings on the skin. These markings have a general pattern resembling the branches of a tree. This fern-like pattern of erythema in the skin is usually found over the shoulders or the flanks. It appears within a few minutes to one hour of an accident. Mechanism: The mechanism by which this pattern occurs has yet to be discovered. It may be caused due to the slight staining of the tissues by haemoglobin from lysed red blood cells along the path of the electric current or rupture of smaller blood vessels at several places giving rise to ecchymoses. They may be superficial bums producing mere erythema of skin which indicates the path taken by the current. They are also said to be due to minute depositions of copper in the dermis or from boiling the intercellular fluid following the fascial planes. They indicate the paths taken by the discharge and disappear in one to two days if the person survives. Red streaks following skin creases or sweat-damped tracks are more likely</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Due to some political clashes, followers of Party “A” attacked and burnt Party “b” house. The police called the forensic team to help them in the investigation. In order to prove that the deceased suffered antemortem burns, which of the following is not a valid point?", "options": [{"label": "A", "text": "Presence of line of redness", "correct": false}, {"label": "B", "text": "Base of blister is red and inflamed", "correct": false}, {"label": "C", "text": "Blister contains serous fluid and proteins", "correct": false}, {"label": "D", "text": "Tissue reaction is absent.", "correct": true}], "correct_answer": "D. Tissue reaction is absent.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Tissue reaction is absent. Marked cellular exudation and reactive changes in the tissue cells present in a case of antemortem burns. ANTEMORTEM VS POSTMORTEM BURNS Characters Antemortem Burns Postmortem Burns Line of redness Present Absent Blister Contain serous fluid with protein & chlorides. The base is red & inflamed. Contain air & thin clear fluid. The base is dry hard and yellow. Soot in respiratory tract May be present Absent Carboxy Hb Present Absent Healing & repair Present Absent Vital reaction Present with reactive changes in the tissues Absent Enzymes Peripheral zone of burn shows increase enzymatic reaction Absent</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A boy was admitted to the pediatric emergency with sclads over his body. Scalding is caused when the liquid in contact has a temperature above", "options": [{"label": "A", "text": "44°C", "correct": false}, {"label": "B", "text": "50°C", "correct": false}, {"label": "C", "text": "60°C", "correct": true}, {"label": "D", "text": "80°C", "correct": false}], "correct_answer": "C. 60°C", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>60°C A scald is an injury which results from the application of liquid above 60°C or from steam.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was brought into the burn emergency with 25% burn over his body. Minimum temp to produce burn is", "options": [{"label": "A", "text": "40°C", "correct": false}, {"label": "B", "text": "44°C", "correct": true}, {"label": "C", "text": "50°C", "correct": false}, {"label": "D", "text": "60°C", "correct": false}], "correct_answer": "B. 44°C", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>44°C A burn is an injury which is caused by the application of heat or chemical substances to the external or internal surfaces of the body, which causes the destruction of tissues. The minimum temperature for producing a burn is about 44 o C for an exposure of about 5 to 6 hours. At 65°C, two seconds are sufficient to produce burns and full-thickness destruction of the skin occurs within seconds> above 70°C.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was working in a brick kiln. He collapsed suddenly and had a high temperature, but there was no sweating. Sweating is absent in:", "options": [{"label": "A", "text": "Heat stroke", "correct": true}, {"label": "B", "text": "Heat syncope", "correct": false}, {"label": "C", "text": "Heat exhaustion", "correct": false}, {"label": "D", "text": "Miner’s cramps", "correct": false}], "correct_answer": "A. Heat stroke", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Heat stroke A burn is an injury which is caused by the application of heat or chemical substances to the external or internal surfaces of the body, which causes the destruction of tissues. The minimum temperature for producing a burn is about 44 o C for an exposure of about 5 to 6 hours. At 65°C, two seconds are sufficient to produce burns and full-thickness destruction of the skin occurs within seconds> above 70°C.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In the below Image, the victim got burnt due to", "options": [{"label": "A", "text": "Scalds", "correct": false}, {"label": "B", "text": "Flame burns", "correct": true}, {"label": "C", "text": "Chemical burns", "correct": false}, {"label": "D", "text": "Any of the above", "correct": false}], "correct_answer": "B. Flame burns", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893585630-QTDF061013IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Flame burns Burns produced by flame may or may not produce vesication, but singeing of the hair and blackening of the skin are always present. Roasted patches of skin or deeper parts may be seen. Dry heat causes burns by direct conduction or radiation to the skin</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A burn patient was found to have an extradural hematoma. Difference between EDH & heat hematoma, favouring heat hematoma is", "options": [{"label": "A", "text": "Limited within the sutures", "correct": false}, {"label": "B", "text": "Firm and homogenous collection", "correct": false}, {"label": "C", "text": "Honeycomb appearance", "correct": true}, {"label": "D", "text": "Seen outside the dura", "correct": false}], "correct_answer": "C. Honeycomb appearance", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Honeycomb appearance Heat haematoma occurs when the head has been exposed to intense heat sufficient to cause charring of the skull. It has the appearance of extradural haemorrhage but is not accompanied by any signs of injury by blunt force. It consists of a soft, friable clot of light chocolate colour and may be pink if the blood contains CO. The clot has a honeycomb appearance due to bubbles of steam produced by heat.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient was brought unconscious with bizarre skin patterns. This kind of skin appearance is seen in", "options": [{"label": "A", "text": "Flame burns", "correct": false}, {"label": "B", "text": "High voltage burns", "correct": true}, {"label": "C", "text": "Lightening", "correct": false}, {"label": "D", "text": "Chemical burns", "correct": false}], "correct_answer": "B. High voltage burns", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893585974-QTDF061015IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>High voltage burns High voltage burns may be very severe with the charring of the body. Multiple individuals and confluent areas of third-degree burn are seen. 1000 volts will jump several mm, and 100 kilovolts about 35 cm. Very high voltage currents produce massive tissue destruction with loss of extremities and rupture of organs. When bone is involved, the periosteum may be elevated, superficial layers of the bone may be destroyed, or fracture may occur. High tension electrical currents may produce multiple, small, discrete, pitted burns due to arcing from the conductor to the body without direct contact. Multiple burnt or punched-out lesions are produced due to the arc dancing over the body surface over large areas, which present 'crocodile flash burns'. Flashover often produces 'arc eye'. High amperage has an explosive blast-like effect and may produce injuries resembling bullet, stab or incised wounds.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A gunshot wound was shaved to clean the area. The area was scorched with singeing of hairs. Scorching results from?", "options": [{"label": "A", "text": "The flame emerging from the muzzle", "correct": true}, {"label": "B", "text": "Grains of gunpowder being driven into the skin", "correct": false}, {"label": "C", "text": "Superficial deposit of smoke on the skin", "correct": false}, {"label": "D", "text": "Deposition of lead or other metal in the skin", "correct": false}], "correct_answer": "A. The flame emerging from the muzzle", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The flame emerging from the muzzle Burning /scorching /singeing of the skin and hair result from the flame that emerges from the muzzle. Gunpowder grains cause tattooing when driven into the skin. Superficial smoke deposition is from burnt gunpowder.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body was recovered in a partially preserved condition with adipocere formation. The ideal condition for Adipocere formation includes?", "options": [{"label": "A", "text": "Warm, humid weather", "correct": true}, {"label": "B", "text": "Dry hot air", "correct": false}, {"label": "C", "text": "Cold, humid air", "correct": false}, {"label": "D", "text": "Cold dry weather", "correct": false}], "correct_answer": "A. Warm, humid weather", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Warm, humid weather Factors influencing adipocere formation: Water helps to remove glycerine which is formed during hydrolysis of the fats. The water required for the hydrolysis is obtained mainly from the body tissues, which therefore become increasingly In a body immersed in water, this fluid contributes to the hydrolysis of the subcutaneous fat. Still, the formation of adipocere in deeper sites starts before the extraneous water enters the body's interior. Activation of lipid peroxidation is a significant component of the mechanism (Manulik eta! 1999). Adipocere is delayed by cold and hastened by heat. A warm, moist, anaerobic environment favours adipocere formation. It is more frequently seen in females, well-nourished mature newborn children, the obese and corpses that have been submerged in water for a long period. It is also seen in buried bodies. Foetuses under seven months do not show this change. The bodies enclosed in a water-tight coffin for many years may be converted to adipocere even without external water.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An alcoholic was found dead on the morning of a cold day. GI system was examined for alcoholic content and other injuries. Wischnevski lesions in autopsy are seen in death due to:", "options": [{"label": "A", "text": "Hypothermia", "correct": true}, {"label": "B", "text": "Strangulation", "correct": false}, {"label": "C", "text": "Head injury", "correct": false}, {"label": "D", "text": "Drowning", "correct": false}], "correct_answer": "A. Hypothermia", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hypothermia Wischnevski lesions are dark-coloured lesions in gastric mucosa-associated with hypothermia</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "FG, FFG, FFFG etc., used in describing gunpowder signifies", "options": [{"label": "A", "text": "Colour of grains", "correct": false}, {"label": "B", "text": "Size of grains", "correct": true}, {"label": "C", "text": "Shape of grains", "correct": false}, {"label": "D", "text": "All", "correct": false}], "correct_answer": "B. Size of grains", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Size of grains FG, FFG, FFFG, etc., depends on the size of the grains. The more F's, the finer the grains and the faster in burning. The powder grains are black, coarse or fine, without any particular shape.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A variable degree of fat necrosis of the pancreas is the most regular post-mortem finding in the case of", "options": [{"label": "A", "text": "Electrocution", "correct": false}, {"label": "B", "text": "Chronic alcoholic", "correct": false}, {"label": "C", "text": "Hypothermia", "correct": true}, {"label": "D", "text": "Diabetes mellitus", "correct": false}], "correct_answer": "C. Hypothermia", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hypothermia POSTMORTEM APPEARANCES OF HYPOTHERMIA:- EXTERNAL:- Pink or brown-pink areas with indistinct, blurred margins, particularly over and around joints such as knees, elbows and hips are characteristic. There may be pink patches on cheeks, chin and nose. The extremities may be cyanosed. Oedema may be seen in the feet and lower legs. PM's lividity is bright pink. INTERNAL: The appearances are not characteristic. The subcutaneous tissues are relatively avascular. Ice crystals can be found in blood vessels, the heart and interstitial tissue spaces. The blood is often bright red due to oxygen retention by haemoglobin at low temperatures. The stomach mucosa is studded with numerous brown-black acute erosions, ulcerations and haemorrhages similar to those seen in many types of pre-death stress. A variable degree of fat necrosis of the pancreas is seen in about 50% of case Areas of stiff, yellow fat necrosis are seen in the pancreas and adjacent areas of omentum and mesentery. Pulmonary oedema and microinfarcts in many organs are common. Perivascular haemorrhages in the brain and small infarcts in the heart are Internal organs are congested.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 30 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 70-year-old man slips and falls in the bathroom. He was immediately rushed to the hospital. What is the conclusion drawn about the given Image below?", "options": [{"label": "A", "text": "Subdural hemorrhage", "correct": true}, {"label": "B", "text": "Extradural hemorrhage", "correct": false}, {"label": "C", "text": "Both of the above", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "A. Subdural hemorrhage", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/questionImage-1682892931573-QTDF044001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Subdural hemorrhage Subdural hemorrhage is more common than extradural hemorrhage. It is common in childhood or old age. This occurs in the subdural space between the dura mater and the arachnoid due to the rupture of parasagittal bridging or communicating veins near the sagittal sinus. These veins are commonly ruptured when the brain moves across the face of the dura. Subdural hemorrhage may occur from relatively slight trauma, often insufficient to cause unconsciousness and usually not producing fractures of the skull, and may be associated with contrecoup contusions. About 70% occur due to falls and assaults and 25% due to vehicle accidents and are especially likely to be found in alcoholics, old persons owing to atrophy or shrinkage of the brain and in children. It may occur in the absence of a fracture of the skull or cerebral contusions or other visible brain It occurs after the head impacts a hard surface and the brain is accelerated, which causes the tearing of the parasagittal bridging veins.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C, & D. Extradural hemorrhage is biconvex in shape in a CT scan. Hence it cannot be the answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During the assault, the victim is physically and emotionally active, due to which the levels of catecholamines increase, and the high blood pressure may cause the rupture of a weak aneurysm. A hard blow to the head may rupture a Berry aneurysm. With respect to this, consider the following statements and pick the incorrect one.", "options": [{"label": "A", "text": "Subarachnoid hemorrhage is caused", "correct": false}, {"label": "B", "text": "Rupture of a saccular Berry aneurysm, which accounts for 95% of aneurysms that rupture", "correct": false}, {"label": "C", "text": "Subarachnoid blood wash off", "correct": true}, {"label": "D", "text": "In acute alcoholism, traumatic subarachnoid hemorrhage is more common", "correct": false}], "correct_answer": "C. Subarachnoid blood wash off", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Subarachnoid blood wash off Subarachnoid blood can be distinguished from subdural blood because subdural blood will wash away under gently running water, whereas subarachnoid blood imparts a red color to the brain that does not wash off.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. During the assault the victim is physically and emotionally active, due to which the levels of catecholamines increase, and the high blood pressure may cause the rupture of a weak aneurysm. A hard blow to the head may rupture a Beny aneurysm. A leaking aneurysm may cause behavioral abnormality leading to conflict with another person, an accident or a fall, and rupture of the Option: B. Causes : Rupture of bridging veins near the sagittal sinus. Focal hemorrhages result from force applied to the head, usually accompanied by shaking of the brain and its coverings within the skull. Lacerations and contusions of the brain and the Rupture of a saccular Berry aneurysm, which accounts for 95% of aneurysms that rupture. In 20 to 30 %of cases, multiple Berry aneurysms rupture. Option: D. In acute alcoholism, traumatic subarachnoid hemorrhage is more common due to loss of muscular coordination, resulting in excessive rotational forces within the head, and also possibly due to increased bleeding from congested vessels which do not contract down, and the bounding pulse of the drunken man. This is the most common form of traumatic intracranial hemorrhage. In all cases of significant brain injury, some degree of subarachnoid hemorrhage is found. It may be the only complication of head injury but is often seen in association with other intracranial hemorrhages, brain injuries, and skull fractures</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The injury can be seen in:", "options": [{"label": "A", "text": "Forehead trauma", "correct": true}, {"label": "B", "text": "Nasal trauma", "correct": false}, {"label": "C", "text": "Zygomatic fracture", "correct": false}, {"label": "D", "text": "Posterior cranial fossa fracture", "correct": false}], "correct_answer": "A. Forehead trauma", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/questionImage-1682892947164-QTDF044003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Forehead trauma Hemorrhages in the soft tissues around the eyes and the eyelids (spectacle hematoma; black eye), may be caused by Direct trauma, such as a punch in the eye, Blunt impact to the forehead, the blood gravitating downwards over the supraorbital bridge, Fracture of the floor of the anterior fossa of the skull. A bruise behind the ear may indicate a basal fracture, rather than a direct blow behind the ear.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect options:- Option: B, C, & D. Nasal trauma, Zygomatic fracture, and posterior cranial fossa fracture does not produce a hematoma around the eyes and eyelids. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A head injury patient was subjected to a CT scan. He was diagnosed with extradural hemorrhage. The minimum amount of blood clot associated with fatalities in extradural hemorrhage:", "options": [{"label": "A", "text": "50 ml", "correct": false}, {"label": "B", "text": "100 ml", "correct": true}, {"label": "C", "text": "250 ml", "correct": false}, {"label": "D", "text": "500 ml", "correct": false}], "correct_answer": "B. 100 ml", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>100 ml Usually, 100 ml is the minimum amount of blood clot associated with fatalities in an extradural The clot is oval or circular, rubbery consistency, reddish-purple, about 10 to 20 em. in diameter, 2 to 6 cm. Thick, weighs 30 to 300 g, and is adherent to the dura mater. The clot is usually in the temporoparietal area or the frontotemporal or parieto-occipital region. Occasionally, it is frontal or seen in the posterior fossa. The hematoma cannot be contrecoup unless the skull has been grossly deformed. If it is bilateral, then trauma has been bilateral or a middle structure, such as the sagittal sinus has been injured.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C, & D. Since the minimum fatal amount is 50ml, other Options are irrelevant.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The appearance of heat hematoma is closely resembling that of:", "options": [{"label": "A", "text": "Subscalp hematoma", "correct": false}, {"label": "B", "text": "Extradural hemorrhage", "correct": true}, {"label": "C", "text": "Subdural hemorrhage", "correct": false}, {"label": "D", "text": "Subarachnoid hemorrhage", "correct": false}], "correct_answer": "B. Extradural hemorrhage", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Extradural hemorrhage Heat hematoma may simulate extradural hemorrhage. Artifacts due to Burns: Heat ruptures may resemble lacerated or incised wounds. Heat hematoma may simulate extradural hemorrhage. An unburnt groove around the neck due to the tightness of the clothes, e.g. collar, may resemble a strangulation mark. In severely burnt bodies, fat droplets may be found in the pulmonary vessels, which should not be mistaken for antemortem pulmonary fat embolism. Radiant heat reaching the body after death may cause loosening or drying and tanning of the skin.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect options:- Option: A, C, & D. Subscalp hematoma, Subdural hemorrhage, or Subarachnoid hemorrhage do not resemble heat hematoma. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 5-year-old male was travelling along with his parents when they were hit by a truck. The child suffered a head injury and NCCT was done for which a provisional report was made- it showed a hyperdense concavo-convex opacity. Later the patient died. During his autopsy examination, the gross examination of the skull reveals: Which of the following statements regarding the following injury is correct?", "options": [{"label": "A", "text": "Death occurs if the hemorrhage is >250 ml.", "correct": false}, {"label": "B", "text": "The cerebral convolution would not retain their normal contour", "correct": false}, {"label": "C", "text": "With slow bleeding, a considerably large subdural haematoma can be tolerated without symptoms or serious side-effects.", "correct": true}, {"label": "D", "text": "Small amounts of subdural haemorrhage are also not spontaneously absorbed.", "correct": false}], "correct_answer": "C. With slow bleeding, a considerably large subdural haematoma can be tolerated without symptoms or serious side-effects.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/questionImage-1682892959309-QTDF044006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>With slow bleeding, a considerably large subdural haematoma can be tolerated without symptoms or serious side-effects. This is a correct statement because, with slow bleeding, accumulated blood gets time to adjust properly according to available space.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. Death occurs if the hemorrhage is >250 ml is a wrong statement as it can also occur if bleeding is 100 or 150 ml Option B. The cerebral convolutions retain their normal contours because the blood presses both the crests and depths of the gyri. Hence option B given above is a wrong statement. Option D. Small amounts of subdural hemorrhage are also not spontaneously absorbed- this is a wrong statement. Small amounts can be absorbed spontaneously.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Father and son were fighting and verbally abusing each other over the dispute over property when the father suddenly collapsed and fell on the ground. He was taken immediately to the hospital but was declared dead. On autopsy examination, when no significant cause was found, his skull was opened and the following finding was noted. Which of the following is the most common spontaneous cause of this condition?", "options": [{"label": "A", "text": "Rupture of bridging vein.", "correct": false}, {"label": "B", "text": "Laceration and contusion of the brain", "correct": false}, {"label": "C", "text": "Rupture of the berry aneurysm", "correct": true}, {"label": "D", "text": "All of the above.", "correct": false}], "correct_answer": "C. Rupture of the berry aneurysm", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/questionImage-1682892972832-QTDF044007IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Rupture of the berry aneurysm In the given image, subarachnoid hemorrhage is shown. The most common cause of spontaneous rupture of SAH is the rupture of a berry aneurysm. During the assault, the victim is physically and emotionally active, due to which the level of catecholamine increases. It can also occur in case of sudden exercise or sexual intercourse.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A & B. Are also an important cause of SAH but not the most common cause. Rupture of bridging veins usually cause SDH.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 48-year-old male was brought to emergency after suffering from RTA. He was unconscious when brought to the emergency, his GCS was poor. After some time the patient gained consciousness and was normal while conversing and explaining the incident to the doctor. He was to undergo NCCT, but there was some ongoing delay of around 7-8 hours in doing so. Suddenly, the patient appeared confused with slurred speech and developed features as if he was drunk eventually the patient slipped into a coma and was intubated to maintain respiratory support. Which of the following phenomena is described above and name the hemorrhage in which this occurs-", "options": [{"label": "A", "text": "Subdural hematoma, phenomena- kernohan notch sign", "correct": false}, {"label": "B", "text": "Epidural hematoma, phenomena- kernohan notch sign", "correct": false}, {"label": "C", "text": "Subdural hematoma, phenomena – lucid interval", "correct": false}, {"label": "D", "text": "Epidural hematoma, phenomena- lucid interval", "correct": true}], "correct_answer": "D. Epidural hematoma, phenomena- lucid interval", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Epidural hematoma, phenomena- lucid interval In the given clinical scenario, the patient after suffering from RTA developed unconsciousness followed by a period of normal consciousness followed by altered sensorium and drunkenness -which is characteristic of lucid interval. This phenomenon is seen in a head injury like epidural hematoma and also in insanity. Epidural hemorrhage is a surgical emergency. It can be treated by creating a burr hole.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & C . Are incorrect as it is not seen in subdural hematoma, and in option A as written kernohan notch sign- it is the ipsilateral pupil dilatation and contralateral hemiparesis and ultimately due to further compression, ipsilateral hemiparesis develops. Option: B. Is also incorrect as this is not a kernohan notch phenomena.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The below Image shows which range of firearm:", "options": [{"label": "A", "text": "Contact range", "correct": false}, {"label": "B", "text": "Close contact range", "correct": false}, {"label": "C", "text": "Intermediate-range", "correct": true}, {"label": "D", "text": "Distant range", "correct": false}], "correct_answer": "C. Intermediate-range", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891631584-QTDF005001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Intermediate-range Intermediate-Range (2 to 4 metres): The minimal distance at which shot mass begins to spread is extremely variable. It may be one metre with a sawed-off shotgun but is usually about two metres with the cylinder bore guns and four metres with full choke guns. At a distance of two metres, the shot mass begins to spread and individual pellet holes may be detected, which are usually round and show a rim of abrasion at their margins. The wound of entry is irregular. Beyond two metres the wads often strike the body below the shotgun wound. It may penetrate the skin or it may only bruise the skin. The wads found within the wounds are useful to determine the bore of the gun. At a distance of three metres: Occasionally, several individual pellet entrance wounds are in contact producing scalloped defects which are larger than the individual pellet holes. As lead is soft, pellets deform easily due to friction as they rub against the inside of the barrel. The heat can cause melting and fusion of pellets.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Point blank range The term 'point blank' is used when the range is very close to or in contact with the surface of the skin. The entrance wound is circular with inverted edges, but the rebounding gases may level up or even evert the margins. The skin is burnt with the singeing of the hair. The skin surrounding the wound is hyperaemic and shows some bruising, burning, blackening and tattooing. Option: B. Close range: Tissues surrounding the wound are singed by flame, blackened by smoke, and tattooed by unburnt or partially burnt powder granules. If the powder is smokeless, there may be greyish or white deposits on the skin around the wound. The deposit of smoke is known as smudging, fouling or blackening. This spreads more widely than powder tattooing. The blackening can be removed with a wet cloth. Unburnt particles of the powder are embedded in the skin producing tattooing (stippling or peppering). The particles sticking to the epidermis or lodging in the epidermis superficially can be removed with pressure wiping, showing punctate wounds. Option: C. Distant range The entrance wound is smaller than the missile due to the elasticity of the skin, circular, and the margins are inverted. Distant entrance wounds of the palms and soles are irregular, often having a stellate appearance, without an abrasion ring, and look like exit wounds. Burning, blackening and tattooing are not seen</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A case of multiple gunshot wounds was brought for autopsy. After exploration with a radiograph, one bullet was found lodged in the body. When a bullet is recovered at autopsy, it should be picked up using the:", "options": [{"label": "A", "text": "Plain forceps", "correct": false}, {"label": "B", "text": "Toothed forceps", "correct": false}, {"label": "C", "text": "Needle", "correct": false}, {"label": "D", "text": "Gloved hands", "correct": true}], "correct_answer": "D. Gloved hands", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Gloved hands Gloved hands are to be used to recover the bullets to avoid adding fingerprints that may obscure latent prints of evidentiary value. To prevent the marring of the bullet surface, it should be removed by plastic forceps or a rubber-tipped bullet extractor.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The stellate wound is seen with the firearm in:", "options": [{"label": "A", "text": "Contact shot", "correct": true}, {"label": "B", "text": "Close Shot", "correct": false}, {"label": "C", "text": "Intermediate shot", "correct": false}, {"label": "D", "text": "Distant shot", "correct": false}], "correct_answer": "A. Contact shot", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Contact shot The contact shot wound is large and triangular, stellate, cruciate or elliptic, showing cavitation due to the expansion of the liberated gases in the skin and tissues, which show laceration.</p>\n<p><strong>Random:</strong></p><p>Explanation for Incorrect Options:- The stellate wound is absent in other ranges of shots.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A bullet carried a lot of markings on it which enables the identification of the weapon. Metallic fouling of the barrel imparts", "options": [{"label": "A", "text": "Primary marking on bullet", "correct": false}, {"label": "B", "text": "Secondary marking on bullet", "correct": true}, {"label": "C", "text": "Tattooing on the victim", "correct": false}, {"label": "D", "text": "Singeing at the entry wound", "correct": false}], "correct_answer": "B. Secondary marking on bullet", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Secondary marking on bullet The surface of the bullet is also grooved by irregularities on the inner surface of the barrel itself (secondary markings; individual or accidental characteristics), which are specific for that particular weapon. These irregularities are produced by the sticking of the particles of the bullet to the bore when shots are fired and are known as 'metallic fouling'.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During viva-voce, a skull with a fracture injury was shown to the candidate. The injury shown in the Image is caused by", "options": [{"label": "A", "text": "Entry gunshot wound", "correct": false}, {"label": "B", "text": "Exit gunshot wound", "correct": true}, {"label": "C", "text": "Drilling in the skull", "correct": false}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "B. Exit gunshot wound", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891631883-QTDF005005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Exit gunshot wound Bevelling is produced when unsupported dipole events and fragments on the side</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Cartridges of rifle and shotgun are different which help in identifying the weapon of offence. Which of the following is associated with shotguns commonly?", "options": [{"label": "A", "text": "Gunpowder", "correct": false}, {"label": "B", "text": "Primer", "correct": false}, {"label": "C", "text": "Projectile", "correct": false}, {"label": "D", "text": "Wads", "correct": true}], "correct_answer": "D. Wads", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Wads Wads are present only in cartridges of smooth-bore (eg:- shotgun) weapons. The wad is made of some soft material like felt, cork, plastic, straw or rug. The cardboard disc behind the shot charge prevents the pellets from getting lodged in the felt wad, separates the propellant from the projectiles, seals the bore effectively and prevents the escape of gas from the breech end. Some wads are disc-shaped, others cup-shaped and still, others have bizarre shapes. Certain modern modifications that may be seen in the imported weapons include the increased use of plastic especially to replace traditional wads. Some of these may be ‘power pistons’ where the shot mass is contained inside the polythene cup, which may also be responsible for producing injuries. In some modern cartridges, plastic granules may be used as filler between the lead pellets, and this highly coloured material may also be found within the wound or upon the skin.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "For calibration of a shotgun, the reference amount of lead used is:", "options": [{"label": "A", "text": "105 gm", "correct": false}, {"label": "B", "text": "250 gm", "correct": false}, {"label": "C", "text": "454 gm", "correct": true}, {"label": "D", "text": "775 gm", "correct": false}], "correct_answer": "C. 454 gm", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>454 gm In a shotgun, for larger bores, the size is determined by the size of the lead ball which will exactly fit the barrel, and by the number of such balls of equal size and weight as can be made from 454 gm. (one pound) of pure lead. Thus the 12-bore gun is one whose diameter is that of a ball of lead of such a size that 12 balls may be made from 454 gm. The smaller the number of gauges, the greater the diameter of the barrel.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Choking is related to which type of firearm:", "options": [{"label": "A", "text": "Pistol", "correct": false}, {"label": "B", "text": "Revolver", "correct": false}, {"label": "C", "text": "Rifle", "correct": false}, {"label": "D", "text": "Shotgun", "correct": true}], "correct_answer": "D. Shotgun", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Shotgun In the choke-bore of a shotgun, the distal seven to ten cm. of the barrel is narrow. Different degrees are known as full-choke, half-choke and quarter-choke or improved cylinders. Some weapons have a facility for removing the bane and replacing it with another degree of choke. The choking lessens the rate of Cylinder spread of shot after it leaves the muzzle, increases the explosive force and increases the velocity. The effective range and penetrating power of a shotgun will depend upon the quantity of propellent charge, size of the shot, length of the barrel and presence or absence of choking</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A, B and C - Pistol, Revolver and Rifle does not have to choke.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Shotgun causes dispersion of pellets and choking is done in the barrel to minimize it. The minimum dispersion of pellets from a shotgun is seen in", "options": [{"label": "A", "text": "Full choked", "correct": true}, {"label": "B", "text": "Half choked", "correct": false}, {"label": "C", "text": "Unchoked", "correct": false}, {"label": "D", "text": "Same in all", "correct": false}], "correct_answer": "A. Full choked", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Full choked As the choking goes from Quarter choked -> Half choked -> Full choked , the dispersion of pellets minimizes. Different degrees are known as full-choke, half-choke and quarter-choke or improved cylinder. Some weapons have the facility to remove the barrel and replace it with another degree of choke. The choking lessens the rate of spread of the shot after it leaves the muzzle, increases the explosive force and increases the velocity</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A circular bullet wound produced by a rifle with an inverted margin with blackening and tattooing but no burning of skin and singeing of hair is in the range of:", "options": [{"label": "A", "text": "Contact", "correct": false}, {"label": "B", "text": "Close", "correct": false}, {"label": "C", "text": "Near", "correct": true}, {"label": "D", "text": "Distant", "correct": false}], "correct_answer": "C. Near", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Near Near Shot : This term is applied when the victim is within the range of powder deposition, and outside the range of flame, and smoke, i.e., up to 50 cm. If the discharge occurs at a distance of about 15cm., the lacerating and burning effects of gases are usually lost due to the dispersion cooling of the gases before they reach the skin. The entrance wound is seen as a round hole, slightly smaller than the diameter of the bullet, due to the elasticity of the skin, with a bruised and inverted margin and a zone of blackening and tattooing. If the bullet strikes the body at an angle, blackening and tattooing have a pear-shaped area, with the larger area on the side nearer the barrel. Abundant gunpowder and a diminishing amount of soot are deposited on the target. As the distance increases, the intensity decreases and blackening and tattooing is spread out over a large area, and there is no singeing of the hair and skin.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A and B. Contact and close contact have burning and singeing of hair. Option: D. Blackening, Tattooing, burning and singeing are absent in distant shot</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Police and the team reached a crime scene where the victim was lying on the ground with a gun in his hand. His shirt was full of blood and there was no other sign of violence detected. On further probing, the house help told that the master just ate dinner and went upstairs for sleeping when he heard the sound of a gunshot. During the investigation of the crime scene what all evidence needs to be collected from the victim?", "options": [{"label": "A", "text": "Photographs are to be taken only after moving all the objects so as to cover the victim clearly.", "correct": false}, {"label": "B", "text": "Gun in the hand of the victim to be collected with bare hands and sent to the lab.", "correct": false}, {"label": "C", "text": "During collecting the firearm from the crime scene, look for the location it is found, the type, and the initials on the butt.", "correct": true}, {"label": "D", "text": "Empty cartridges and shells need not be collected.", "correct": false}], "correct_answer": "C. During collecting the firearm from the crime scene, look for the location it is found, the type, and the initials on the butt.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891671208-QTDF006001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>During collecting the firearm from the crime scene, look for the location it is found, the type, and the initials on the butt. During collecting the firearm from the crime scene, look for the location it is found, type, and initials on the butt- this is a correct statement. The firearm should be looked for all these things while collected in a paper and afterwards sent to the laboratory. At the crime scene, photographs should be taken before any item is moved from various angles to show the position of various items. Photographs should also be taken of single items when they are moved. Hence option A is incorrect.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Gun from the victim's hand should be collected with the help of a piece of paper and not bare hands as fingerprints will get imprinted on this. Option: D. Empty cartridges, shells, wads everything found at the scene of the crime should be collected.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You have recovered a bullet from the body of Mr Ashok, chief marketing officer of Mahindra group. The gun from which the bullet was fired was recovered from his personal assistant, Seema. For further investigation, the swab was taken from his hand to test for gunpowder residues. Which of the following is the most appropriate test to do for testing it?", "options": [{"label": "A", "text": "Dermal nitrate test", "correct": false}, {"label": "B", "text": "Harrison and Gilroy test", "correct": false}, {"label": "C", "text": "Atomic absorption spectroscopy (AAS)", "correct": false}, {"label": "D", "text": "Flameless atomic absorption spectroscopy. (FAAS)", "correct": true}], "correct_answer": "D. Flameless atomic absorption spectroscopy. (FAAS)", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Flameless atomic absorption spectroscopy. (FAAS) In the given question the most reliable test for detecting gunpowder residues will be flameless atomic absorption spectroscopy > atomic absorption spectroscopy. Hence d is a better answer than c.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . Dermal nitrate test is not done nowadays. Harrison and Gilroy's test is also used to detect certain residues like pb, sb, ba etc. But the better answer here will be option d.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "From the body of the victim, the following bullet was recovered. Which of the following option is the correct answer for this question?", "options": [{"label": "A", "text": "Frangible bullet", "correct": false}, {"label": "B", "text": "Tandem bullet", "correct": false}, {"label": "C", "text": "Ricochet bullet", "correct": false}, {"label": "D", "text": "Mushroom bullet.", "correct": true}], "correct_answer": "D. Mushroom bullet.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891673068-QTDF006003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mushroom bullet. In the given question, the image depicts an altered shape of the bullet after being fired from the firearm and penetrating the body. The shape appears like that of a mushroom, hence it is named a mushroom bullet.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Frangible bullet- the bullet entering the body is broken up into several fragments and each part produces injury to the body. Option: B. Tandem bullet- when the entry track shows more than one bullet, but the shape is not altered. This is important wrt to the old unused firearm. Option: C. Ricochet bullet- the bullet after being fired from the gun gets deflected due to some obstacle is ricochet bullet.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 30-year-old male was found lying in his room with a gunshot in the head from the right side. The gun was lying in his hand. On collection of the evidence and the gun, the fingerprint detected was of the victim himself. Further corroborative findings suggest it to be a suicide. Which of the following findings suggest the event to be a suicide except-", "options": [{"label": "A", "text": "Wound seen on the vital parts and accessible parts of the body.", "correct": false}, {"label": "B", "text": "Range of firing is near shot range.", "correct": true}, {"label": "C", "text": "Suicide handgun wounds occur in the head (80%), chest (15%) and abdomen (< 5%).", "correct": false}, {"label": "D", "text": "Weapons used to fire may be held firmly in the hand by the victim, gripped tightly in a cadaveric spasm.", "correct": false}], "correct_answer": "B. Range of firing is near shot range.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Range of firing is near shot range. In case of a suicide wound, the range of the firearm is contact shot range. Hence it is not found in the case of suicide wounds.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Generally the suicide wound is present on the accessible part and vital parts of the body. Hence it is a correct statement. Option: C. Suicide handgun wounds occur in the head (80%), chest (15%) and abdomen (< 5%) is a correct statement. Option: D. Weapon used to fire may be held firmly in the hand by the victim, gripped tightly in a cadaveric spasm. It is also observed that the left-handed victim will make a fire on the left side of the head.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 14 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A road traffic victim was taken to the emergency. The type of injury shown in the Image is", "options": [{"label": "A", "text": "Blunt", "correct": false}, {"label": "B", "text": "Penetrations", "correct": false}, {"label": "C", "text": "Blast", "correct": false}, {"label": "D", "text": "Crush", "correct": true}], "correct_answer": "D. Crush", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892622858-QTDF033001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Crush If the blunt force produces extensive bruising and laceration of deeper tissues, it is called a \"crushing\" injury. The force may be produced by some moving weapon or object or by a fall. Other Options A, B, and C: Blunt, Penetrative or Blast injuries don't produce such extensive yet localized Hence are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient with a head injury was examined by a junior resident. He marked the forehead wound as an incised wound. The consultant pointed out it as a lacerated wound. Incised-looking lacerations are examples of", "options": [{"label": "A", "text": "Avulsions", "correct": false}, {"label": "B", "text": "Split lacerations", "correct": true}, {"label": "C", "text": "Chop wounds", "correct": false}, {"label": "D", "text": "Tear lacerations", "correct": false}], "correct_answer": "B. Split lacerations", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Split lacerations Incised-like or Incised-looking Wounds : Split lacerations produced without excessive skin crushing may have relatively sharp margins. Blunt force on areas where the skin is close to the bone, and the subcutaneous tissues are scanty, may produce a wound that by the linear splitting of the tissues (as the skin is easily stretched during impact), may look like an incised The sites are the scalp, eyebrows, cheekbones, lower jaw, iliac crest, perineum, and shin. A wound produced by a fall on the knee or elbow with the limb flexed, and by a broken glass or sharp stone also simulates an incised</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A . Avulsion (shearing laceration): An avulsion is a laceration produced by sufficient force (shearing force) delivered at an acute angle to detach (tear off) a portion of a traumatized surface or viscus from its attachments. Option: C . Chop Wound - A wound caused by a heavy weapon or instrument with at least one sharp cutting edge—e.g., axe, machete, panga; often the wound has abraded margins—which may be scraped off—and maybe thus confused with a laceration; chop wounds over bone may have a groove or cut in the underlying bone—e.g., skull. Option: D . Tear Laceration - Tearing of the skin and tissues can occur from impact by or against irregular or semi-sharp objects, such as the door handle of a car.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A hits B with a blunt weapon on the head. B goes into a coma and later dies. No gross postmortem findings are noted in B. Cause of death is given as diffuse axonal injury. An important finding in such cases is", "options": [{"label": "A", "text": "Subdural hemorrhage", "correct": false}, {"label": "B", "text": "Subarachnoid hemorrhage", "correct": false}, {"label": "C", "text": "Extradural hemorrhage", "correct": false}, {"label": "D", "text": "Retraction Balls", "correct": true}], "correct_answer": "D. Retraction Balls", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Retraction Balls After 12 hours of injury, the axons first appear dilated, then club-shaped, and finally appear as round balls known as \"retraction balls\", which indicate transected axons indicating diffuse axonal injury. The number of retraction balls begins to decrease 2 to 3 weeks after injury, and clusters of microglial cells appear, followed by astrocytosis and demyelination.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options: - Other Options A B and C: Subdural, Subarachnoid, and Extradural hemorrhages are not findings in Diffuse Axonal Injury. Hence these options are not the correct options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The below-seen injury is called as", "options": [{"label": "A", "text": "Avulsion laceration", "correct": false}, {"label": "B", "text": "Incised wound", "correct": false}, {"label": "C", "text": "Lacerated-looking incised wound", "correct": false}, {"label": "D", "text": "Incised-looking lacerated wound", "correct": true}], "correct_answer": "D. Incised-looking lacerated wound", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892623183-QTDF033004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Incised-looking lacerated wound Incised-like or Incised-looking Wounds :- Lacerations produced without excessive skin crushing may have relatively sharp margins. Blunt force on areas where the skin is close to the bone, and the subcutaneous tissues are scanty, may produce a wound that by the linear splitting of the tissues (as the skin is easily stretched during impact), may look like an incised The sites are the scalp, eyebrows, cheekbones, lower jaw, iliac crest, perineum, and shin. A wound produced by a fall on the knee or elbow with the limb flexed, and by a broken glass or sharp stone also simulates an incised</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Avulsion (shearing laceration): An avulsion is a laceration produced by sufficient force (shearing force) delivered at an acute angle to detach (tear off) a portion of a traumatized surface or viscus from its attachments. Option B: Incised Wound - A clean, straight cut caused by a sharp edge (i.e. a knife) and is usually longer than it is deep. It tends to bleed heavily as multiple vessels may be cut directly across. Connecting structures such as ligaments and tendons may also be involved. Option C: Lacerated-Looking Incised Wounds- These wounds are seen in areas with rugae or irregular skin like the scrotum.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted with multiple injuries over the body. The attending resident was making MLC; however, he was not able to interpret some of the injuries accurately. Lacerated wound resembles incised wound on:", "options": [{"label": "A", "text": "Scalp", "correct": true}, {"label": "B", "text": "Thigh", "correct": false}, {"label": "C", "text": "Gluteal region", "correct": false}, {"label": "D", "text": "Anterior abdominal wall", "correct": false}], "correct_answer": "A. Scalp", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Scalp Incised–like or Incised–looking wounds: Blunt force on areas where the skin is close to the bone, and the subcutaneous tissues are scanty, may produce a wound which by the linear splitting of the tissue, may look like an incised wound</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C, & D Injuries over the thigh, gluteal region, and abdomen do not create such misinterpretation.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted to the emergency with multiple stab wounds over the chest and abdomen. He was scheduled for laparotomy. Which of the following statements is true about stab wounds?", "options": [{"label": "A", "text": "Has entry and exit wound", "correct": false}, {"label": "B", "text": "Breadth is maximum", "correct": false}, {"label": "C", "text": "Depth is more than length & breadth", "correct": true}, {"label": "D", "text": "Has irregular margins and is broader than the edge of the weapon", "correct": false}], "correct_answer": "C. Depth is more than length & breadth", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Depth is more than length & breadth Stab or Puncture Wound: A stab wound is produced from the penetration of a pointed instrument, such as a knife, dagger, nail, needle, spear, arrow, screwdriver, etc.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A A stab wound does not always have an exit. Options B & D These are not the characteristics of a stab wound.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was beaten black and blue by police personnel in lockup with batons. Ante mortem bruise is identified best by which of the following?", "options": [{"label": "A", "text": "Colour changes", "correct": false}, {"label": "B", "text": "Bleeding", "correct": false}, {"label": "C", "text": "Histology", "correct": true}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "C. Histology", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Histology On histology of the wound, a post-mortem wound would not show any cellular changes, evidence of edema, RBCs, etc.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect Options:- Option: A & B. Color changes and bleeding also suggest antemortem nature but histology is the best to study. Color changes and bleeding also suggest antemortem nature but histology is the best to study.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A resident posted in the emergency was noting the injuries of an assault victim. He was careful in interpreting every injury. Site notorious for incised looking Lacerated wounds is all except:", "options": [{"label": "A", "text": "Chest", "correct": true}, {"label": "B", "text": "Zygoma", "correct": false}, {"label": "C", "text": "Iliac crest", "correct": false}, {"label": "D", "text": "Shin", "correct": false}], "correct_answer": "A. Chest", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Chest The chest is not an area where subcutaneous tissues are scanty and the skin is not close to the bones. We have breast fatty tissues between the skin and the rib bones. Hence incised looking lacerated wounds are not seen usually in the chest region.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options B, C & D Incised–like or Incised–looking wounds: Blunt force on areas where the skin is close to the bone, and the subcutaneous tissues are scanty, may produce a wound which by the linear splitting of the tissue, may look like an incised wound. They occur whenever there is thin subcutaneous tissue between skin and bone like the Scalp, forehead, Zygoma, Iliac crest, Shin, Incised–like or Incised–looking wounds: Blunt force on areas where the skin is close to the bone, and the subcutaneous tissues are scanty, may produce a wound which by the linear splitting of the tissue, may look like an incised wound. They occur whenever there is thin subcutaneous tissue between skin and bone like the Scalp, forehead, Zygoma, Iliac crest, Shin,</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The following test for lie detection is known as?", "options": [{"label": "A", "text": "Polygraph test", "correct": true}, {"label": "B", "text": "Narco-analysis", "correct": false}, {"label": "C", "text": "Hypnosis", "correct": false}, {"label": "D", "text": "Word association", "correct": false}], "correct_answer": "A. Polygraph test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Polygraph test Polygraph makes a continuous record of blood pressure, pulse, respiration, muscular movements and electrodermal reaction changes in response to stimuli in the form of questions. It is based on the theory, that when the person tells a lie in answer to a question, and there is fear that lies will be detected, the emotion of fear results in stimulation of the sympathetic nervous system which is detected by the polygraph.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Narcoanalysis: (\"truth serum\" drugs): This test involves the intravenous administration of a drug (such as sodium pentothal, sodium seconal, scopolamine and sodium amytal) that causes the subject to enter into various stages of anaesthesia. In the hypnotic stage, the subject becomes less inhibited and is more likely to divulge information, which would usually not be revealed in the conscious state. Option: C. Hypnosis: Many people cannot be hypnotised and many cannot be hypnotised to a deep level. It does not often enhance memory. Hypnotised witnesses produce more fabricated recollections, are more influenced by the interviewer's misleading comments and questions, and are more confident in the accuracy of their recollections, than are non-hypnotised witnesses, even when their recollections are false. Option: D. Word Association: Changes in reaction time of the subject's reply to word stimuli, either visual or auditory, or by the stereotype of answers, or by an exhibition of uncoordinated physical movements, have been employed in attempts to detect deception.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A suspect in a bomb blast was sentenced to a polygraph test by the court. The following findings are conclusive of a positive polygraph test(that the patient is lying) except?", "options": [{"label": "A", "text": "Blood pressure and pulse rate increases", "correct": false}, {"label": "B", "text": "Erratic and Slowing down of respiration", "correct": false}, {"label": "C", "text": "Increased involuntary muscle movements", "correct": true}, {"label": "D", "text": "Lowering of galvanic skin resistance", "correct": false}], "correct_answer": "C. Increased involuntary muscle movements", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Increased involuntary muscle movements There is a relative rise in blood pressure, pulse rate increases(Option A), slowing down of the breathing, erratic breathing (Option B), and many times suppression of involuntary muscular movements(Option C), and lowering of the galvanic skin resistance of the individual due to increased activity of sweat glands(Option D). All these are recorded in a polygraph and used to detect lies.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 30-year-old criminal was subjected to narco analysis following a court order. The truth serum drugs used in narco analysis are all except?", "options": [{"label": "A", "text": "Scopolamine hydrobromide", "correct": false}, {"label": "B", "text": "Sodium amytal", "correct": false}, {"label": "C", "text": "Sodium seconal", "correct": false}, {"label": "D", "text": "Ketamine", "correct": true}], "correct_answer": "D. Ketamine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Ketamine Narcoanalysis: (\"truth serum\" drugs): This test involves the intravenous administration of a drug (such as sodium pentothal, sodium seconal, scopolamine and sodium amytal) that causes the subject to enter into various stages of anaesthesia. In the hypnotic stage, the subject becomes less inhibited and is more likely to divulge information, which would usually not be revealed in the conscious state.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C. Scopolamine hydrobromide, Sodium seconal and Sodium amytal are usually used as truth serum drugs in Narcoanalysis. Hence are correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A suspect in a terrorist attack was taken for brain mapping to find his response when the details of the crime are presented before him. Find the true statement from the below-given options", "options": [{"label": "A", "text": "4 types of stimuli are presented", "correct": false}, {"label": "B", "text": "Truth serum is used before brain mapping", "correct": false}, {"label": "C", "text": "A MERMER is emitted by the brain when the suspect has previous knowledge of the details of the crime", "correct": true}, {"label": "D", "text": "An equipment called an electro cap is fixed on the suspect's head for recording MEG", "correct": false}], "correct_answer": "C. A MERMER is emitted by the brain when the suspect has previous knowledge of the details of the crime", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A MERMER is emitted by the brain when the suspect has previous knowledge of the details of the crime</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: D. Equipment called Electro cap is fixed for recording EEG and not MEG A specific wave response called MERMER- (memory encoding related multifaceted electroencephalographic response) is elicited when the brain processes the relevant information it recognises. The pattern occurs within about a second after the stimulus presentation Option: A. Three types of stimuli are present targets, irrelevant and probes. The target illicit a MERMER Option: B. Brain mapping doesn’t use truth serum</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The below-given image below shows", "options": [{"label": "A", "text": "Brain mapping", "correct": true}, {"label": "B", "text": "Narco analysis", "correct": false}, {"label": "C", "text": "Hypnosis", "correct": false}, {"label": "D", "text": "Polygraph", "correct": false}], "correct_answer": "A. Brain mapping", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892433898-QTDF026006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Brain mapping The given Image shows the instrument used for Brain mapping.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C & D.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A dead body was brought for autopsy with asphyxial signs. It has multiple injuries over the body. Bruising of soft tissues of the anterior neck with fracture of the thyroid cartilage and hyoid bone is seen in", "options": [{"label": "A", "text": "Ligature Strangulation", "correct": false}, {"label": "B", "text": "Throttling.", "correct": true}, {"label": "C", "text": "Traumatic asphyxia.", "correct": false}, {"label": "D", "text": "Hanging.", "correct": false}], "correct_answer": "B. Throttling.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Throttling. THROTTLING OR MANUAL STRANGULATION: - Asphyxia produced by compression of the neck by human hands is called throttling. Death occurs due to occlusion of carotid arteries. Occlusion of the airway plays a minor Post-mortem Appearances: External: -Bruises on the neck: The situation and extent of the bruised areas on the neck will depend upon the relative positions of the assailant and victim, the manner of grasping the neck, and the degree of pressure exerted upon the throat. The bruises are produced by the tips or the pads of the fingers. Their shape may be oval or round and of the size of the digits ( 1.5 to 2 cm.), but continued bleeding into the contused area usually increases the size with fracture of hyoid bone and thyroid cartilage.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options : A, C & D. Both hyoid and thyroid fracture is not seen in ligature strangulation, Traumatic asphyxia or hanging. Hence these are the wrong options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following is NOT a cause of death due to suffocation?", "options": [{"label": "A", "text": "Smothering", "correct": false}, {"label": "B", "text": "Choking", "correct": false}, {"label": "C", "text": "Gagging", "correct": false}, {"label": "D", "text": "Throttling", "correct": true}], "correct_answer": "D. Throttling", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Throttling THROTTLING OR MANUAL STRANGULATION: - Asphyxia produced by compression of the neck by human hands is called throttling. Death occurs due to occlusion of carotid arteries. Occlusion of the airway plays a minor role.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B & C. Suffocation Suffocation is a general term to indicate that form of asphyxia, where air entry to the lungs is prevented by any means other than the pressure on the neck or drowning. It includes smothering, choking and gagging.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Inward compression fractures of the hyoid bone are seen in the following:", "options": [{"label": "A", "text": "Partial hanging", "correct": false}, {"label": "B", "text": "Complete hanging", "correct": false}, {"label": "C", "text": "Throttling", "correct": true}, {"label": "D", "text": "Gagging", "correct": false}], "correct_answer": "C. Throttling", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Throttling Inward Compression Fractures:- This is seen in the case of throttling, where the main force is an inward compression acting on the hyoid bone. The fingers of the grasping hand squeeze the greater horns towards each other so that the bone may be fractured within one cm of the tip, and the posterior fragment is displaced inwards.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & B. Outward compression fractures are usually seen in hanging and not inward compression. Hence these two options are not the correct Option: D. Gagging doesn't involve any inward compression fracture. Hence it is not the correct answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The hyoid bone fracture was found in a case of asphyxia with diffuse injuries over the neck. Hyoid bone fracture is most commonly associated with the following:", "options": [{"label": "A", "text": "Hanging", "correct": false}, {"label": "B", "text": "Throttling", "correct": true}, {"label": "C", "text": "Ligature strangulation", "correct": false}, {"label": "D", "text": "Gagging", "correct": false}], "correct_answer": "B. Throttling", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Throttling It is agreed that the injuries to the superior horns or cornuae of the thyroid cartilage and greater horns of the hyoid bone are considerably more frequent in manual strangulation than hanging and are normally related to the state of ossification of these structures.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D. Hyoid bone fracture is more commonly seen in throttling than ligature strangulation, hanging or gagging.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body was recovered from under the vehicle and admitted to the emergency. The attending doctor suspected traumatic asphyxia. All can cause traumatic asphyxia except", "options": [{"label": "A", "text": "Railway accident", "correct": false}, {"label": "B", "text": "Accidental strangulation", "correct": true}, {"label": "C", "text": "Stampede", "correct": false}, {"label": "D", "text": "Bomb blast injury in closed space", "correct": false}], "correct_answer": "B. Accidental strangulation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Accidental strangulation Children may get entangled in ropes during play, or the neck may be caught in window cords, etc. Infants are sometimes strangled in their cots when the neck is caught inside bars, in restraints, braces, etc. Occasionally, an infant is strangled with a string attached to a toy tied to the crib. Persons under the influence of alcohol, epileptics, and imbeciles may be strangled by a tight scarf or collar and necktie. It may occur if an intoxicated person rests their neck against a bar or other hard object. It may occur when a string used in suspending a weight on the back slips from across the forehead and compresses the neck. In industry, belts, ropes or parts of clothing may be caught in the rollers or other parts of the moving machinery and cause accidental strangulation. Accidental strangulation may occur in the uterus when the movement of the fetus causes the umbilical cord to encircle the neck. In such cases, there is a relatively slight cervical tissue injury. Wharton's jelly is not damaged, and lungs are usually incompletely expanded.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Railway accidents, stampedes and bomb blasts in closed spaces can cause traumatic asphyxia. Hence are true Options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Family members brought a person to the emergency. There was a mark over the neck, and the attending resident suspected strangulation. He at once informed the police. Which of the following is a characteristic feature of strangulation?", "options": [{"label": "A", "text": "Fracture of the thyroid cartilage is present", "correct": false}, {"label": "B", "text": "Fracture of the cricoid cartilage is present", "correct": false}, {"label": "C", "text": "Fracture dislocation of cervical vertebrae", "correct": false}, {"label": "D", "text": "Extravasation of blood under the ligature mark and rupture of neck muscles", "correct": true}], "correct_answer": "D. Extravasation of blood under the ligature mark and rupture of neck muscles", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Extravasation of blood under the ligature mark and rupture of neck muscles Strangulation by a ligature- The ligature mark is transverse/horizontal, completely encircling the neck below the thyroid cartilage. The base is soft and reddish, with ecchymoses & haemorrhages. Fracture of thyroid cartilage: more common. Emphysematous bullae: Very common on the surface of the lungs. Face: Congested, livid and marked with petechiae.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Tongue: Swelling and protrusion are more marked Option: A. Fracture of the thyroid cartilage is not always present Option: B. Fracture of the cricoid cartilage is present in manual strangulation Option: C. Fracture dislocation of cervical vertebrae is seen in judicial hanging.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Family members brought a person to the emergency. They claimed that he was strangulated. In strangulation, there are:", "options": [{"label": "A", "text": "External signs of asphyxia are not well marked", "correct": false}, {"label": "B", "text": "Neck muscles rupture is common", "correct": true}, {"label": "C", "text": "Fracture dislocation of cervical vertebrae", "correct": false}, {"label": "D", "text": "All of the above", "correct": false}], "correct_answer": "B. Neck muscles rupture is common", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Neck muscles rupture is common S.NO Trait Hanging Strangulation by ligature (1) Ligature mark: It is oblique, does not completely encircle the neck; usually seen high up in the neck between the chin and larynx. The base is pale, hard and parchment-like. It is transverse, completely encircling the neck below the thyroid cartilage The base is soft and reddish. (2) Abrasions and ecchymoses: About the edges of ligature mark not common. About the edges of the ligature mark are common. (3) Bruising: of the neck muscles less common. Of the neck muscles more common. (4) Neck: Stretched and elongated. Not stretched or elongated. (5) Subcutaneous tissues: White, hard and glistening under the mark. Ecchymosed under the mark. (6) Hyoid bone: Fracture may occur. Fracture is uncommon. (7) Thyroid cartilage: Fracture is less common. Fracture is more common. (8) Larynx and trachea: Fracture rare. Fractures may be found. (9) Emphysematous bullae: Not present on the surface of the lungs. Very common on the surface of the lungs. (10) Carotid arteries: Damage may be seen. Damage is very rare. (11) Face: Usually pale and petechiae are not common. Congested, livid and marked with petechiae. (12) Signs of asphyxia: External signs less marked. External signs well-marked. (13) Tongue: Swelling and protrusion are less marked. Swelling and protrusion are more marked. (14) Saliva: Often runs out of the mouth. Absent. (15) Bleeding: From the nose, mouth and ears are not common. From the nose, mouth and ears common. (16) Involuntary discharge: Of faeces and urine less common. Of faeces and urine more common (17) Seminal fluid: At glass is more common. At glass is less common.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Burking is smothering and:", "options": [{"label": "A", "text": "Throttling", "correct": false}, {"label": "B", "text": "Strangulation", "correct": false}, {"label": "C", "text": "Gagging", "correct": false}, {"label": "D", "text": "Traumatic asphyxia", "correct": true}], "correct_answer": "D. Traumatic asphyxia", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Traumatic asphyxia Burking: It includes homicidal smothering and traumatic asphyxiation, named after Burke and Hare Burke used to sit on the chest of the victim and close his mouth and nostrils by hand and Hare used to pull him round the room by foot.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C. Throttling, strangulation and gagging are not involved in burking.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "‘Fractures a la signature’ is:", "options": [{"label": "A", "text": "Fissured fracture", "correct": false}, {"label": "B", "text": "Gutter fracture", "correct": false}, {"label": "C", "text": "Depressed fracture", "correct": true}, {"label": "D", "text": "Ring fracture", "correct": false}], "correct_answer": "C. Depressed fracture", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Depressed fracture Depressed fracture –‘fractures la signature’, fracture bone is driven inwards to the skull cavity Comminuted fracture – multiple fractures Pond or indented fracture –seen in infants.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Fissured fracture – linear fracture involving the whole thickness of the bone or inner or outer table only - most common type. Option: B. Gutter fracture – part of the thickness of the bone is removed and may be seen in bullet injury. Option: D. Ring fracture – encircles the base of the skull around the foramen magnum Diastatic fracture – involving sutures, commonly seen in children. Hinge Fracture – Motorcyclists fracture Fracture of the base of the skull where the fracture line runs from side to side across the floor of the middle cranial fossa.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A dead body was brought for autopsy with a history of strangulation by police personnel. The most important sign of death from ligature strangulation is", "options": [{"label": "A", "text": "Fracture of hyoid bone", "correct": false}, {"label": "B", "text": "Fracture dislocation of cervical vertebrae", "correct": false}, {"label": "C", "text": "Horizontal ligature mark with ecchymosis around the edges.", "correct": true}, {"label": "D", "text": "Tardieu’s spot over conjunctiva", "correct": false}], "correct_answer": "C. Horizontal ligature mark with ecchymosis around the edges.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Horizontal ligature mark with ecchymosis around the edges. Strangulations -2 common types: Throttling -manual strangulation - Marks of pressure by the thumb and fingertips are usually found on either side of the trachea. Linear or crescentic abrasion marks produced by the nails. ligature strangulation - Ligature mark completely encircling the neck horizontally, usually at or below the level of the thyroid Face is highly congested (maximum congestion of face) Strangulation by other means: Bansdola – was practised in Northern India. Garrotting –official method of execution in Spain – Spanish windlass Mugging – strangulation caused by compressing the neck in the elbow bent or knee bent. In a “commando punch”, – the edge of the hand strikes across the side of the neck or front of the larynx – which may trigger cardio-inhibitory reflexes.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. fracture of the hyoid bone is seen in hanging. Option: B. fracture dislocation of the cervical vertebra is seen in judicial hanging. Option: D. Tardieu spots are seen in any asphyxia death.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 28-year-old female was brought to emergency after spillage of hot water onto his abdomen and below. On examination, the skin was sodden and bleached. Vesicles were present over the burnt area. Which of the following additional features in this patient will point towards injury from moist heat? Red line of demarcation present. Charring singeing or ulceration present. Site of injury will be at the level and below the site of contact. Cause can be flame or heated solid body or X-ray. Select the correct answer from given below code:-", "options": [{"label": "A", "text": "1,2,3", "correct": false}, {"label": "B", "text": "1,3", "correct": true}, {"label": "C", "text": "2,4", "correct": false}, {"label": "D", "text": "3,4", "correct": false}], "correct_answer": "B. 1,3", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,3 In the given question, the patient was burned by hot water, so it is a form of moist heat. The features in favour of moist heat from the above options are- Red line of demarcation present. The site of injury will be at the level and below the site of contact because Moist Heat example, Hot liquids, can tickle down, so the site of injury can be below the site of contact.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Charring, singing and ulceration will be absent in case of moist heat. Hence it is the wrong The cause of injury can be a heated solid body, flame or x-ray in dry heat. Hence this is also an incorrect statement.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A small child of 5 years of age accidentally got burned on the lower limb due to a fall of hot boiled soup. He was immediately brought to the hospital for treatment. Which of the following statement is not correct wrt scalds?", "options": [{"label": "A", "text": "A scald is an injury resulting from applying liquid above 60°C or steam.", "correct": false}, {"label": "B", "text": "Water at 70°C can cause full-thickness scalds of the skin in one second of contact", "correct": false}, {"label": "C", "text": "An antemortem blister does not show hyperaemia in the surrounding area, and the floor is not red.", "correct": true}, {"label": "D", "text": "Redness appears immediately, and blistering will occur within a few minutes.", "correct": false}], "correct_answer": "C. An antemortem blister does not show hyperaemia in the surrounding area, and the floor is not red.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>An antemortem blister does not show hyperaemia in the surrounding area, and the floor is not red. These changes are present in antemortem burns because of vital reactions. Option: C. is an incorrect statement, as the postmortem burns will not show hyperemia in the surrounding area, and the floor is not red.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. A scald is an injury resulting from applying liquid above 60°C or from steam- is a true statement. Option: B. Water at 70°C can cause full-thickness scalds of the skin in one second of contact is also a correct statement. Option: D. Redness appears immediately, and blistering will occurs within a few minutes. And the blister will contain fluid which contains white cells and red cells.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 38-year-old male was brought to the hospital following being found lying on the street after a heavy rainy day. You observed the following type of pattern on the body of the patient. What is it called, and why does it occur?", "options": [{"label": "A", "text": "Lichtenberg figures- due to hemolysis and haemoglobin staning of the tissue.", "correct": true}, {"label": "B", "text": "Joule burn- point of contact between light striking and skin.", "correct": false}, {"label": "C", "text": "Filigree burn- along the lymphatics.", "correct": false}, {"label": "D", "text": "Joule burn- represents the path of current.", "correct": false}], "correct_answer": "A. Lichtenberg figures- due to hemolysis and haemoglobin staning of the tissue.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893619688-QTDF062003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lichtenberg figures- due to hemolysis and haemoglobin staning of the tissue. The given image depicts the formation of Lichtenberg figures, also known as arborescent markings or filigree burns. It is formed due to hemolysis and haemoglobin staining of the tissue along the current path.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B & D. are incorrect as it is not a joule So you can rule out these options easily. Option: C . Filigree burn- along the lymphatics- is also known as filigree burns. Still, it does not occur along the line of lymphatic because It is formed due to hemolysis and haemoglobin staining of the tissue along the current path.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During your emergency duty, you noticed three patients who were present there had suffered from scalds. Patient A- complained of blisters around the hand where the hot coffee had spilt. Patient B was a child in excruciating pain due to burning over the buttock while taking a bath with his mother, who mistakenly poured hot water on his bumps. He had developed erythema and redness.Patient C was a 22-year-old female who accidentally got oil spilt on his right hand and abdomen while cooking in the house. There was necrosis of the dermis. Arrange the following sets of patients in increasing order of the degree of burn.", "options": [{"label": "A", "text": "A>B>C", "correct": false}, {"label": "B", "text": "B>C>A", "correct": false}, {"label": "C", "text": "C>A>B", "correct": false}, {"label": "D", "text": "B>A>C", "correct": true}], "correct_answer": "D. B>A>C", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>B>A>C In the given question, Patient A- has a blister due to the increased permeability of the capillaries. Patient B- has erythema and redness, which have developed due to vasoparalysis. So, it has the maximum degree of burn. Patient C- has necrosis of the dermis. Hence the order for increasing the degree of scalds will be B>A>C. So, option D is the correct</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During your internship in the FMT department, you came across a painting hanging at the department entrance given below. You seem to find its resemblance to a distinct type of burn found in victims of lightning strokes. Which of the following statements is not true regarding the condition it resembles to-", "options": [{"label": "A", "text": "It is most specific for lightning.", "correct": false}, {"label": "B", "text": "Most commonly seen over shoulders, flanks and front of the chest.", "correct": false}, {"label": "C", "text": "Even if the person survives, these marks will not be removed from the body.", "correct": true}, {"label": "D", "text": "Deposition of copper along the path of discharge.", "correct": false}], "correct_answer": "C. Even if the person survives, these marks will not be removed from the body.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893619688-QTDF062005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Even if the person survives, these marks will not be removed from the body. These markings will resolve spontaneously in 1-2 days if the patient survives,e. Litchenberg burns are not permanent. Hence option C is the incorrect one. In the given question, the painting in the image describes a Lichtenberg pattern present in cases of people struck by lightning stroke. The correct statement regarding this given in the above options are:-</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Opti on: A. It is the most specific sign. It is also known as filigree burn, arborescent markings. They are superficial, irregular and tortuous markings which resemble branches of a tree or a fern. Option: B. Most commonly seen over the shoulders, flanks, and front of the chest is a correct statement. Option: D. There occurs deposition of copper along the path of discharge.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 28-year-old G3P2L2 female went for defecation at her home early morning, and she did not feel any pain. After defecation, she found that her baby was delivered into the lavatory pan. She complained that she was not able to distinguish the sense of fullness produced by the descent of a child from the feeling of bulky evacuation. She brought the dead baby along with her to the Emergency Department. What is this condition known as?", "options": [{"label": "A", "text": "Stillborn", "correct": false}, {"label": "B", "text": "Dead-born", "correct": false}, {"label": "C", "text": "Precipitate Labour", "correct": true}, {"label": "D", "text": "Liveborn", "correct": false}], "correct_answer": "C. Precipitate Labour", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Precipitate Labour Labour terminating in a very short time than taken on the average, either in primiparae or multiparae is called Precipitate Labour. In this, delivery occurs suddenly and rapidly without any knowledge of the mother. All 3 steps of labour are merged into one. It is possible in multiparae with a large roomy pelvis, but very rare in primiparae. They may not be able to distinguish the sense of fullness produced by the descent of a child from the feeling of evacuation. The child may die from - Suffocation by falling into the lavatory pan, head injury, and fracture of the skull with subdural haemorrhage often bilateral, by a fall on a hard floor or haemorrhage from the torn fetal end of the cord. MLI - Mother may be falsely charged with Infanticide; Mother may actually kill the child and blame it on precipitate labour. Precipitate Labour - Here all three stages of labour are merged into one thereby labour happening in a very short period of time thereby happening rapidly even without the knowledge of the The process of labour is usually complete within 3 hrs.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . Stillborn - A stillborn child is born after 28 weeks of pregnancy and does not breath or show any other signs of life at any time after being completely born. Option: B. Dead-born - The child here dies in Utero and shows the following signs after it is born- Rigor Mortis, Robert Sign, Maceration, Spalding’s Sign, and Mummification. Option: D. Liveborn - If the fetus gets delivered after 28 weeks and respires at least once is known as liveborn. Various tests are present to confirm it - Wredin’s Test, Breslau’s 2nd life test, Plocquet’s test, etc.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A newborn child was strangulated by his uncle and brought dead to the Casualty department. You filed an MLC report and handed it to the Police. The court summoned You and there the Judge asked You, \"How did You interpret that the child was born alive?\". You presented with the autopsy report of the child and presented that before birth the middle ear contains gelatinous connective tissue but no air, and after birth, it contains air replacing the gelatinous substance, so the child was liveborn. This test performed by You is known as-", "options": [{"label": "A", "text": "Wredin’s Test", "correct": true}, {"label": "B", "text": "Fodere’s Test", "correct": false}, {"label": "C", "text": "Breslau 2nd Life Test", "correct": false}, {"label": "D", "text": "Hydrostatic Test", "correct": false}], "correct_answer": "A. Wredin’s Test", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Wredin’s Test Wredin’s Test - Air in the Middle ear is positive for Wredin’s test. Before birth, the middle ear contains gelatinous embryonic connective tissue but no air. With respiration, the sphincter at the pharyngeal end of the Eustachian tube relaxes and air replaces the gelatinous substance in a few hours to five weeks. The middle ear must be opened under water by removing tegmen tympani. A bubble of air comes out if the test is Positive. These changes in the Middle Ear are tested by Wredin’s Test.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Fodere’s Test - Also known as Static Test. The lungs are ligated across their hila and separated. The average weight of both lungs before respiration varies from 30-40g and after respiration from 60-66g. The increase in weight is due to the increased flow of blood. Option: C. Breslau’s 2nd Life Test - When air is detected in the stomach or intestines it is known as Breslau’s Second Life Test. Option: D. Hydrostatic Test - Hydrostatic test is based on the specific gravity of the lungs which is less than that of water will float, otherwise will sink, in it entire lung is placed in water separately along with a piece of the liver as a control.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A test was performed by a Forensic Senior Resident to asses the signs of Livebirth in a brought dead infant in the Emergency Department of a Govt. hospital. The test done was based on the fact that on breathing, the volume of the lungs is increased which more than compensates for the weight of the additional blood, due to which their specific gravity is diminished. But after the test, the expanded lungs sinked, it may be due to: Pulmonary Edema Artificial Respiration Decompensation by gas in the lungs Alveolar Duct Membrane Air absorbed by lung. Select the correct answer from the given below code:", "options": [{"label": "A", "text": "1, 2, 3, 4, and 5", "correct": false}, {"label": "B", "text": "1, 4, and 5", "correct": true}, {"label": "C", "text": "2, 3, and 4", "correct": false}, {"label": "D", "text": "2, 4, and 5", "correct": false}], "correct_answer": "B. 1, 4, and 5", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1, 4, and 5 Hydrostatic Test is the test performed in the case. It is based on the Specific gravity of the lung tissue comparative of before and after respiration. The lung tissue floats in water along with a piece of liver used as a control. If the lungs float separately, then they are cut into 12-20 small pieces and then submerged again in water. Now if they float, they are squeezed above a sponge and then submerged again. Now if they float, it is indicative of Livebirth as the lungs then contain some residual air. There may be some fallacies as in both respired lungs but not floating and also in non-respired lungs but floating., False -ve and False +ve respectively. The expanded lungs may sink from- Atelectasis (non-expansion) of the lungs due to air not entering the lungs due to feeble respiration, acute edema, pneumonia, congenital syphilis, complete absorption of air from the lungs by the blood( if circulation continued after stoppage of respiration), obstruction by Alveolar duct membrane. False +ve in case of - Putrefactive gases, artificial inflation. Pulmonary edema, Alveolar Duct Membrane and Air absorbed by the lung shows False -ve case when expanded lungs may sink.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Artificial Respiration and decompensation by gas in the lungs causes False +ve Hydrostatic Test., so the option is wrong. Option: C. Decompensation by gas in the lungs shows Unexpanded lungs to float, False +ve. Option: D. Artificial Respiration shows Unexpanded lungs to float, False+ve.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A liveborn child was brought dead to the ER, after an MLC report being filed by the duty doctor, an autopsy was performed. The external findings were noted and changes in the umbilical cord were recorded. The cut end of the cord indicated a non-institutional delivery which was attended by a midwife, the best match for the vital signs in the umbilical cord indicating it to be a liveborn child is:- Drying up of cut margin - 2hrs Drying up of cord - 10 days Cord detachment - 5-6 days Inflammatory line at the base of the stump- 1 month Completing healing (scar formation)- 10-12 days Select the correct answer from the given below code:", "options": [{"label": "A", "text": "1, 3, and 5", "correct": true}, {"label": "B", "text": "2, 4, and 5", "correct": false}, {"label": "C", "text": "1, 3, and 4", "correct": false}, {"label": "D", "text": "2, 3, and 4", "correct": false}], "correct_answer": "A. 1, 3, and 5", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1, 3, and 5 The liveborn child is viable and after getting delivered it respired once. A viable infant may have 3 outcomes- Deadborn (the child was dead in utero.); Stillborn(the child was alive in the uterus but died during the process of delivery) and Liveborn. Signs of Liveborn- Baby’s cry- strong evidence in favour of live birth and respiration having taken place. The fetus may inhale air and cry when the head is inside the vagina- vagitus vaginalis, or inside the uterus - vagitus uterinus; Muscle twitching/ movements of limbs; Sneezing, and yawning. On the assessment of the case, a determination of the viability is done. After the determination of live birth a cause of death is assigned. The changes in the umbilical cord are seen as- The appearance of the cut end of the cord may help to decide whether the birth was one where a medical, nursing or midwife or only an amateur person was available. The cut end of the cord should be looked for vital reaction, even when early putrefaction renders an evaluation of breathing impossible, vital signs in the cord may indicate live birth if survival reached 24-48 hrs. Drying of cut margin- 2hrs (statement 1) Drying up of cord- 1 day (statement 2) The inflammatory line at the base of the stump- 2 days (statement 4) Obliteration and mummification changes- 3 days Cord detachment- 5-6 days (statement 3) Complete healing (scar formation)- 10-12 days (statement 5) 1, 3, and 5 are the correct match for the changes in the umbilical cord.</p>\n<p><strong>Random:</strong></p><p>Explanation for the incorrect Options:- Option: B. Drying up of cord appears at- 1day and Inflammatory line at the base of the stump- 2 days is the correct option. Option: C. Inflammatory line at the base of the stump- 2 days is the correct option for the change. Option: D. Drying up of cord- 1day and Inflammatory line at the base of the stump- 2 days is the correct option for the change.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A test was performed on the lung tissues obtained by autopsy of a dead infant. The tissues were submerged in water and their sinking or floating was noted along with a tissue of the liver which was used as control tissue. The final test result was as seen in the image given below. Choose the correct option from the given below options.", "options": [{"label": "A", "text": "The infant was a liveborn, as the lung tissues sink due to more specific gravity.", "correct": false}, {"label": "B", "text": "The infant was a liveborn, as the lung tissues float due to less specific gravity.", "correct": true}, {"label": "C", "text": "The lungs were edematous but sink due to putrefying gases.", "correct": false}, {"label": "D", "text": "The test was False positive as the child suffered from congenital syphilis.", "correct": false}], "correct_answer": "B. The infant was a liveborn, as the lung tissues float due to less specific gravity.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892002092-QTDF019007IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The infant was a liveborn, as the lung tissues float due to less specific gravity. The hydrostatic test /Raygat test is shown above. It is based on the principle that the lung tissues float in a liveborn child due to less specific gravity than water. If the tissue float- Respired lung If the tissue sink- Unrespired lung In it, the lungs are separated and placed in water along with a liver tissue sample which is used as a control. If the lung floats, it is then cut into 12-20 small pieces, and is then again placed in water. Now if the lung tissues float they are squeezed under water, if air bubbles are seen, they are removed under water and are squeezed above a sponge. Now, also if the tissues float, It indicates that the lung contains residual air which cannot be removed and is assumed to be Liveborn. False +ve Hydrostatic test seen in - Accumulation of putrefying gases or artificial inflation. False -ve Hydrostatic test is seen in - Atelectasis, Congenital Syphilis. The infant was a liveborn, as the lung tissues float due to less specific gravity than water, so it is the correct match.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. The lungs float in the image, it shows the child was liveborn, due to less specific gravity than water. Option: C. Edematous lungs sink (False-ve) in cases of- Atelectasis, Congenital Syphilis, Feeble respiration, Alveolar Duct Membrane, etc. Option: D . False +ve Hydrostatic test is seen in - Accumulation of putrefying gases or artificial inflation.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was caught secretly burying the dead body of a child and intentionally concealing the birth of the child. The Police arrested him and presented him in front of the Court, and was sent to 2 years imprisonment with a fine. The child was deadborn, but Infanticide was not proved. Under which charges was the person punished?", "options": [{"label": "A", "text": "Concealment of Birth - IPC 318", "correct": true}, {"label": "B", "text": "Abandoning of Children- IPC 317", "correct": false}, {"label": "C", "text": "Infanticide - IPC 302", "correct": false}, {"label": "D", "text": "Culpable homicide of child in mother's womb - IPC 299", "correct": false}], "correct_answer": "A. Concealment of Birth - IPC 318", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Concealment of Birth - IPC 318 This is a case of Concealment of birth along with disposing of the dead body of the child, charged under Sec. 318 of the IPC. In it whoever secretly buries or otherwise disposes of the dead body of the child, whether such child dies before or after or during its birth, intentionally conceals the birth of the such child, shall be punished with imprisonment up to 2 years. If the child whose dead body is so disposed is of a girl child, the person with rigorous imprisonment for a term which may extend to 5 years and shall also be liable to a fine which may extend to fifty thousand rupees. It does not matter whether the child died before or after or during its birth. In a case where infanticide is not proven, the person is usually charged under this section. It is charged under IPC 318. Concealment of Birth - IPC 318, The person who secretly buries or disposes of the dead body of a child and intentionally conceals the birth of a such child is punished with imprisonment of 2 years with/ without fine.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Abandoning of Children- IPC 317, deals with abandoning by the father or mother of the child under the age of 12 years with imprisonment up to 7 years with/ without fine. Option: C. Infanticide - IPC 302, It is charged the same as the murder of any other individual, Punishable by death or imprisonment for life and fine. Option: D. The causing of the death of a living child in the mother’s womb may amount to Culpable homicide, if any part of that child has been brought forth, though the child may not have breathed or completely born (Sec. 299IPC).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "When any human organ is to be removed from the body of a person in the event of his brain-stem death, no such removal shall be undertaken unless such death is certified, by a Board of medical experts. The board should be consisting of all of the following except:", "options": [{"label": "A", "text": "The registered medical practitioner, in charge of the hospital in which brain-stem death has occurred", "correct": false}, {"label": "B", "text": "An independent registered medical practitioner, being a specialist, to be nominated by the registered medical practitioner in charge of the hospital in which brain-stem death has occurred", "correct": false}, {"label": "C", "text": "A neurologist or a neurosurgeon to be nominated by the registered medical practitioner in charge of the hospital in which brain-stem death has occurred", "correct": false}, {"label": "D", "text": "The ICU in charge of the hospital in which brain-stem death has occurred", "correct": true}], "correct_answer": "D. The ICU in charge of the hospital in which brain-stem death has occurred", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The ICU in charge of the hospital in which brain-stem death has occurred The ICU in charge of the hospital in which brainstem death has occurred need not be present on the board.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, B & C Where any human organ is to be removed from the body of a person in the event of his brain-stem death, no such removal shall be undertaken unless such death is certified, in such manner and on the satisfaction of such conditions and requirements as may be prescribed, by a board of medical experts consisting of the following, namely: The registered medical practitioner in charge of the hospital in which brain stem death has occurred An independent registered medical practitioner being a specialist, to be nominated by the registered medical practitioner specified in clause from the panel of names approval by the appropriate authority A neurologist or a neurosurgeon to be nominated by the registered medical practitioner specified in clause from the panel of names approved by the appropriate authority The registered medical practitioner treating the person whose brain stem death has occurred</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body of a hanging victim was brought for autopsy. After postmortem, the body should be handed over to:", "options": [{"label": "A", "text": "Magistrate", "correct": false}, {"label": "B", "text": "Patient’s relatives", "correct": false}, {"label": "C", "text": "Local Inspector", "correct": false}, {"label": "D", "text": "Investigating officer", "correct": true}], "correct_answer": "D. Investigating officer", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Investigating officer In a medico-legal autopsy, the dead body is in the custody of the Investigating Officer till the post-mortem examination, and not the relatives or Medical Superintendent of the hospital, hence it should be handed over to the I.O. after the post-mortem examination is complete. The I.O. then hands over the body to the relatives.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A & C. The body can be handed over to a magistrate or local inspector only if he is the investigating officer. Option: B. The body is not handed over to the patient's relatives. The Investigating Officer hands it over to the relatives after Legal formalities.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In a case of postmortem, a magistrate came as an investigating officer. In India, magistrate inquest is done in the following cases, EXCEPT:", "options": [{"label": "A", "text": "Exhumation cases", "correct": false}, {"label": "B", "text": "Dowry deaths within 5 years of marriage", "correct": false}, {"label": "C", "text": "Murder cases", "correct": true}, {"label": "D", "text": "Death of a person in police custody", "correct": false}], "correct_answer": "C. Murder cases", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Murder cases The inquest is a legal inquiry into the cause of death where death is apparently not due to natural causes. In India, in most cases (whether suicide, murder, or accident) the inquest is done by police (under section 174 Crpc).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A, B & D Magistrate inquest is done in only three conditions (under section 176 Crpc): By Executive Magistrate: Death of a woman within 7 years of marriage Exhumation- By Judicial Magistrate: Custodial Deaths</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An unknown body was found near a seashore. The local people informed the police about it. The body was later sent for autopsy. What is the kind of autopsy done on the body to find out the manner of death?", "options": [{"label": "A", "text": "Pathological autopsy", "correct": false}, {"label": "B", "text": "Medicolegal autopsy", "correct": false}, {"label": "C", "text": "Psychological autopsy", "correct": true}, {"label": "D", "text": "Any of the above", "correct": false}], "correct_answer": "C. Psychological autopsy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Psychological autopsy Medicolegal autopsy:- The main aim is to find out the cause of death, whether natural or unnatural. This is done by detecting, describing, and recording any external or internal injuries, abnormalities, and diseases. To find out how the injuries occurred. To find out the manner of death, whether accidental, suicidal, or homicidal. To find out the time since death. To establish identity when not known. To collect physical evidence in order to identify the object causing death and to identify the criminal. To retain relevant organs and tissues as evidence. In newborn infants, to determine the question of live birth and viability</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Pathological Autopsy: The hospital pathologist has easy access to relevant information about the history, physical condition, and course of the disease leading to death. The history directs the pathologist to the appropriate ancillary investigations. The main aim is to find morphologic changes (extent of a known disease) explaining signs or symptoms of the disease and the effectiveness of treatment. It helps to determine the cause of death, the extent of natural disease, or the combination of comorbidities that led to death. It detects previously unrecognized disease. It helps the family to know of inheritable conditions present in the deceased. Option: C. PSYCHOLOGICAL AUTOPSY: Psychological autopsy is a set of postmortem investigative procedures that help ascertain and evaluate the role that physical and psychological factors play in the death of a victim of suicide, thus to determine the manner of death to as high a degree of certainty as possible</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person “ x” died at home by hanging at home. The police interviews the “x”'s family members, friends, and coworkers. Employers and fellow students, who had dealt with “X”. What is the term given to such kind of autopsy?", "options": [{"label": "A", "text": "Pathological autopsy", "correct": false}, {"label": "B", "text": "Medicolegal autopsy", "correct": false}, {"label": "C", "text": "Psychological autopsy", "correct": true}, {"label": "D", "text": "Both B and c", "correct": false}], "correct_answer": "C. Psychological autopsy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Psychological autopsy Psychological autopsy is a set of postmortem investigative procedures that help ascertain and evaluate the role that physical and psychological factors play in the death of a victim of suicide, thus to determine the manner of death to as high a degree of certainty as possible. It involves the systematic collection of psychological data through structured interviews with the deceased's family members. friends, coworkers. Employers and fellow students, who had dealt with the deceased. Data are sought about his medical, educational, sexual, marital, employment, alcohol, drugs, phobias, moods, interpersonal relationships, friends and colleagues, personality coping style, psychiatric history, and general emotional life, judging abilities, concentration, l.Q. and chronology of events leading up to the time of committing suicide. When it is combined with first-person accounts of the deceased's last days of life, i.e. evidence from the site of death, police investigation reports and archival documents, e.g. medical and mental health records, school, and occupational records, previous suicide attempts and financial records, conclusions can be drawn as to the of the deceased and therefore his role in causing his own death.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Pathological Autopsy: The hospital pathologist has easy access to relevant information about the history, physical condition, and course of the disease leading to death. The history directs the pathologist to the appropriate ancillary investigations. The main aim is to find morphologic changes (extent of a known disease) explaining signs or symptoms of the disease and the effectiveness of treatment. It helps to determine the cause of death, the extent of natural disease, or the combination of comorbidities that led to death. It detects previously unrecognized disease. It helps the family to know of inheritable conditions present in the deceased. Option: B. Medicolegal autopsy:- The main aim is To find out the cause of death, whether natural or unnatural. This is done by detecting, describing, and recording any external or internal injuries, abnormalities, and diseases. To find out how the injuries occurred. To find out the manner of death, whether accidental, suicidal, or homicidal. To find out the time since death. To establish identity when not known. To collect physical evidence in order to identify the object causing death and to identify the criminal. To retain relevant organs and tissues as evidence. In newborn infants, to determine the question of live birth and viability</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "There was a death on the operation table as soon as the anesthetist started induction of anesthesia. In a medicolegal investigation of alleged death due to anesthesia, all of the following are correct statements except", "options": [{"label": "A", "text": "Blood samples of the cadaver must be taken", "correct": false}, {"label": "B", "text": "Devices introduced into the patient, such as endotracheal tubes, catheters, etc. must be removed before starting the autopsy", "correct": true}, {"label": "C", "text": "Injuries due to resuscitative measures may mimic strangulation", "correct": false}, {"label": "D", "text": "Radiographs of the dead body must be taken before the autopsy", "correct": false}], "correct_answer": "B. Devices introduced into the patient, such as endotracheal tubes, catheters, etc. must be removed before starting the autopsy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Devices introduced into the patient, such as endotracheal tubes, catheters, etc. must be removed before starting the autopsy Surgical and Anesthetic devices introduced into the patient should not be removed before the autopsy. Attendance of the clinician at autopsy is important in a case of death due to anesthesia. Full clinical information is essential. Surgical and anesthetic devices introduced into the patient should not be removed before autopsy. In deaths from inhalation anesthesia, the odor of the anesthetic agent may be detected at autopsy. Examine in situ all the cavities. Measure the contents or fluids and preserve them for analysis. Examine sites at surgical intervention in situ and describe them in detail. Dissect all the organs and inspect every surgical suture. Engorgement of the dependent parts of the viscera is usually seen in cases of prolonged anesthesia.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A painter fell from the second floor while painting the exterior surface of the apartment. He was rushed into hospital. After investigation, he was found to have multiple lower limb fractures including the pelvis. However, he succumbed to death after 6 hours of admission into the hospital. Fat globules from which artery is noticed while doing anautopsy?", "options": [{"label": "A", "text": "Pulmonary artery", "correct": true}, {"label": "B", "text": "Pulmonary vein", "correct": false}, {"label": "C", "text": "Popliteal artery", "correct": false}, {"label": "D", "text": "Popliteal vein", "correct": false}], "correct_answer": "A. Pulmonary artery", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pulmonary artery If fat embolism is suspected, the pulmonary artery should be dissected under water and the escape of fat droplets noted. Other Options B, C, and D: Pulmonary vein, Popliteal artery, and popliteal vein are not relevant vessels to look for fat embolism. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An HIV-positive patient died in an RTA. The forensic expert was supposed to conduct an autopsy of the patient. Which of the following methods of organ removal would be appropriate?", "options": [{"label": "A", "text": "Rokitansky method", "correct": true}, {"label": "B", "text": "Lettulle’s method", "correct": false}, {"label": "C", "text": "Ghon’s method", "correct": false}, {"label": "D", "text": "Virchow’s method", "correct": false}], "correct_answer": "A. Rokitansky method", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Rokitansky method Rokitansky's technique: It involves in situ dissection in part, combined with en block removal. It is a preferred choice in patients with highly transmissible diseases, such as HIV, and hepatitis B.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Lettulle's technique: Cervical, thoracic, abdominal, and pelvic organs are removed en masse and dissected as organ block. It has the advantage of leaving all attachments intact. Option: C. Ghon's Technique: Cervical, thoracic, abdominal organ,s and urogenital system are removed as organ blocks. The neuronal system is removed as another block. Option: D. Virchow's technique: Individual organs are removed one by one. The cranial cavity is exposed first, followed by the thoracic, cervical, and abdominal organs. The spinal cord is removed from the back. In this, the anatomico-pathologic relations are not preserved</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A forensic postgraduate student is directed by his HOD to conduct an autopsy. The PG student opens the cranial cavity first, followed by the thoracic cavity and later the abdominal cavity and he removes the organs one by one from each cavity. What is the name of such an approach in the removal of organs?", "options": [{"label": "A", "text": "Virchow’s technique", "correct": true}, {"label": "B", "text": "Rokitansky method", "correct": false}, {"label": "C", "text": "Lettulle’s method", "correct": false}, {"label": "D", "text": "Ghon’s method", "correct": false}], "correct_answer": "A. Virchow’s technique", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Virchow’s technique Virchow's technique: Individual organs are removed one by one. The cranial cavity is exposed first, followed by the thoracic, cervical, and abdominal organs. The spinal cord is removed from the back. In this, the anatomico-pathologic relations are not preserved.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Rokitansky's technique: It involves in situ dissection in part, combined with en block removal. It is the preferred choice in patients with highly transmissible diseases, such as HIV and hepatitis B. Option: C. Lettulle's technique: Cervical, thoracic, abdominal, and pelvic organs are removed en masse and dissected as organ block. It has the advantage of leaving all attachments intact. Option: D. Ghon's Technique: Cervical, thoracic, abdominal organs, and urogenital system are removed as organ blocks. The neuronal system is removed as another block.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A farmer was brought to the ER by his family members. However, on examining the patient, the doctor declared him to be dead. Autopsy was conducted later on. No exact cause of death was concluded. The toxicological analysis also proved to be negative. What is his kind of autopsy called as?", "options": [{"label": "A", "text": "Negative autopsy", "correct": true}, {"label": "B", "text": "Obscure autopsy", "correct": false}, {"label": "C", "text": "Virtual autopsy", "correct": false}, {"label": "D", "text": "Psychological autopsy", "correct": false}], "correct_answer": "A. Negative autopsy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Negative autopsy When gross and microscopic examination, toxicological analyses, and laboratory investigations fail to reveal a cause of death, the autopsy is considered to be negative A negative autopsy may be due to Inadequate history Deaths from vagal inhibition status epilepticus, hypersensitivity reaction, laryngeal spasm in drowning, etc. may not show any anatomical findings. Inadequate external examination: The presence of fresh and old needle marks may be missed on cursory examination in a drug addict. Death from snake bites and insect bites cannot be explained unless the bite marks are identified. The burn may be missed in electrocution. Inadequate or improper internal examination: Air embolism and pneumothorax are often missed. Insufficient laboratory examinations. Lack of toxicological analysis. Lack of training of the doctor.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. OBSCURE AUTOPSIES are those which do not show a definite cause for death, in which there are minimal, indefinite, or obscure findings or even no positive findings at all. They are a source of confusion to any pathologist. Frequently, these deaths are due to obscure natural causes, but they may be due to certain types of injury or complications of injury, or poisoning. Mild degrees of natural disease should not be implicated unless other possibilities are most carefully eliminated. Option: C. VIRTUAL AUTOPSY (VIRTOPSY): It is a non-invasive technique of examining dead bodies to find out the cause of death. It does not destroy some important evidence that may be destroyed in the usual autopsy. It is a combination of CT and MR imaging. CT images give information about morbid anatomical findings and MR imaging demonstrates soft tissue injury, organ trauma, state of blood vessels, tissue, and bones. MR spectroscopy measures metabolites formed due to decomposition, which helps to estimate the time since death. Option: D. PSYCHOLOGICAL AUTOPSY: Psychological autopsy is a set of postmortem investigative procedures that help ascertain and evaluate the role that physical and psychological factors play in the death of a victim of suicide, thus to determine the manner of death to as high a degree of certainty as possible</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 25-year-old person developed right corneal opacity following an injury. The left eye was already having poor vision. The vision was restored following corneoplasty. Medico-legally this injury should be labeled as:", "options": [{"label": "A", "text": "Simple", "correct": false}, {"label": "B", "text": "Grievous", "correct": true}, {"label": "C", "text": "Dangerous", "correct": false}, {"label": "D", "text": "Serious", "correct": false}], "correct_answer": "B. Grievous", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Grievous Permanent privation of the sight of either eye:- The gravity of such injury lies in its permanency because it deprives a person of the use of the organ of sight and also disfigures him. It can be caused by gouging out of eyes, poking eyes, chemicals, etc. Permanent loss does not mean that it should be incurable, e.g. loss of sight occurring due to corneal opacity resulting from injury to the cornea may be curable by corneoplasty. It constitutes grievous injury.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, C, & D: Permanent privation of sight is a grievous hurt. Hence simple injury is ruled out. Dangerous and serious injury is not among the classification. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person after being hit by lathis is admitted to a hospital for 20 days. Which of the following indicates grievous hurt?", "options": [{"label": "A", "text": "Wounds have not completely healed", "correct": false}, {"label": "B", "text": "Some wounds are infected", "correct": false}, {"label": "C", "text": "The person is not able to do his daily pursuits", "correct": true}, {"label": "D", "text": "He was suffering from severe pain for twelve days", "correct": false}], "correct_answer": "C. The person is not able to do his daily pursuits", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The person is not able to do his daily pursuits Grievous hurt 8th clause:- Any hurt which endangers life, Any hurt which causes the victim to be in severe bodily pain for 20 days, and Any hurt which prevents the victim from following his ordinary pursuits for 20 The three clauses are independent of each other, and hurt of any of the three clauses would be a grievous hurt.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & B . Infected and unhealed wounds need not be Grevious hurt necessarily. Hence these two options are not the correct answers. Option: D . Suffering severe bodily pain for 20 days or more is classified under grievous hurt. 12 days is not the correct answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A lacerated wound commonly appears like an incised wound when it occurs at:", "options": [{"label": "A", "text": "Scalp", "correct": true}, {"label": "B", "text": "Chest", "correct": false}, {"label": "C", "text": "Abdomen", "correct": false}, {"label": "D", "text": "Leg", "correct": false}], "correct_answer": "A. Scalp", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Scalp Incised-like or Incised-looking Wounds : Lacerations produced without excessive skin crushing may have relatively sharp margins. Blunt force on areas where the skin is close to the bone, and the subcutaneous tissues are scanty, may produce a wound which by the linear splitting of the tissues (as the skin is easily stretched during impact), may look like an incised The sites are the scalp, eyebrows, cheekbones, lower jaw, iliac crest, perineum, and shin. A wound produced by a fall on the knee or elbow with the limb flexed, and by a broken glass or sharp stone also simulates incised wound.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C, & D: Incised looking Lacerated wounds occur in bony prominences. Hence, these wounds cannot occur in the chest abdomen and leg(exception shin). So these options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was stabbed in his right forearm when he was trying to ward off the attack. A stab wound having an entry and exit wound is called:", "options": [{"label": "A", "text": "Punctured", "correct": false}, {"label": "B", "text": "Penetrating", "correct": false}, {"label": "C", "text": "Perforating", "correct": true}, {"label": "D", "text": "Harakiri", "correct": false}], "correct_answer": "C. Perforating", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Perforating Perforating wounds or through-and-through puncture wounds:- The wound of entry is larger with inverted edges, and the wound of exit is smaller with everted edges, due to the tapering of the The victim of a fatal penetrating injury may not show signs and symptoms of injury until many hours have passed.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A . A puncture Wound is a wound created in a hollow organ. Hence it is not the correct answer. Option: B . Perforating wound is a wound when the depth is usually more than the length and width of the wound. It need not have an exit wound. Hence it is not the correct answer. Option: D . Harakiri is a method of suicide where the sword is entered through the abdomen and the intestine is twisted and even taken out at times. The person dies due to vagal inhibition and not due to bleeding.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 29-year college student was going home after a party at his friend’s house. On the way back to his house he got into a road rage when his bike accidentally hit the car of a stranger. The stranger got angry and hit him hard below his belt with a hard kick. The man cried aloud and was unconscious. The Police intervened and took him to hospital and arrested the other guy. In the hospital, he was assessed by the doctor, and after proper examination and further investigations, it was revealed that his genitalia was severely damaged and it will lead to impotency in the future. An FIR was filed against the other guy and he was charged by the Court. Under which section will he be convicted now for this crime?", "options": [{"label": "A", "text": "Sec. 326IPC", "correct": false}, {"label": "B", "text": "Sec. 325IPC", "correct": true}, {"label": "C", "text": "Sec. 323IPC", "correct": false}, {"label": "D", "text": "Sec. 326A IPC", "correct": false}], "correct_answer": "B. Sec. 325IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec. 325IPC It is a case of Grievous hurt which led to the Emasculation of the man. It will be punished under Sec. 325IPC which is for the punishment for voluntarily causing grievous hurt: imprisonment for a term extending to 7 years and also a 320IPC defines Grievous hurt, as the hurt of a more serious nature. It is very difficult to draw a line between those bodily hurts which are serious and those which are slight. The hurt under grievous hurt must be some specific hurt, voluntarily inflicted and coming within any of the eight kinds enumerated as- Emasculation Permanent privation of the sight of either eye. Permanent privation of the hearing of either ear. Privation of any joint or member. Destruction or permanent impairing of the power of any member or joint. Permanent disfiguration of the head or face. Fracture or dislocation of a bone or tooth. Any hurt which endangers life, or which causes the victim to be in severe bodily pain, or unable to follow his ordinary pursuits for twenty days. It means depriving a male of masculine vigor. Amputation of the penis, injuries to the genitals or head, fracture pelvis with injury to the parasympathetics, and fracture spine at the level of first lumbar 4 and 5 with injury to sacral segments of the spinal cord (ergenitus nerve) can cause emasculation. Injury to the genital branch of the genito-urinary nerve can result in impotence. If the testes are removed before puberty, impotence is the rule, but if they are removed after puberty potency is retained. A simple injury is neither extensive nor serious and heals rapidly. Grievous hurt will be punished under Sec. 325IPC which is for the punishment for voluntarily causing grievous hurt: imprisonment for a term extending to 7 years and also a</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. 326IPC - Voluntarily causing grievous hurt by dangerous weapon or means, where dangerous weapon or means include any instrument for shooting, stabbing or cutting or any instrument, which used as a weapon of offense, is likely to cause death; fire or any heated substance; poison or any corrosive substance; explosive substance or any substance which is harmful to the human body to inhale, to swallow or to receive into the human blood. Option: C. 323IPC - Punishment for voluntarily causing hurt: imprisonment up to one year, or with a fine up to one thousand rupees or both. Option: D. 326A IPC - Voluntarily causing grievous hurt by use of acid, etc. Is punishable with imprisonment of not less than 10 years, but may extend to life, and with a fine. Sec 326B IPC is for voluntarily throwing or attempting to throw acid, imprisonment of not less than 5 years, and also a fine.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A thief entered the house of a 25-year-old corporate working girl at night when everyone was sleeping. She heard him and caught the thief, who on running away pushed the girl and hit her with a knife which caused a cut on the bridge of the nose even though the internal wall separating the nostrils was intact. The police were called and they arrested the thief and took the girl to the doctor. This type of injury was called under the heading of the permanent disfiguration of the head or face, which of the following is a correct statement regarding this type of bodily hurt?", "options": [{"label": "A", "text": "It was a Grievous hurt although the injury was not endangering her life.", "correct": true}, {"label": "B", "text": "Disfigure means to cause some internal injuries which weakens someone from the inside.", "correct": false}, {"label": "C", "text": "Grievous hurt also prevents the victim from following his professional pursuits for 6 months.", "correct": false}, {"label": "D", "text": "Loss of eyesight occurring due to corneal opacity which can be recovered after surgery is not a grievous hurt.", "correct": false}], "correct_answer": "A. It was a Grievous hurt although the injury was not endangering her life.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>It was a Grievous hurt although the injury was not endangering her life. It is a case of Grievous hurt (Sec.320IPC), which is a hurt of more serious nature. It is very difficult to draw a line between those bodily hurts which are serious and those which are slight. The hurt under grievous hurt must be some specific hurt, voluntarily inflicted and coming within any of the eight kinds enumerated as- Emasculation; permanent privation of the sight of either eye; permanent privation of the hearing of either ear; privation of any joint or member; destruction or permanent impairing of the power of any member or joint; permanent disfiguration of the head or face; fracture or dislocation of a bone or tooth; any hurt which endangers life, or which causes the victim to be in severe bodily pain, or unable to follow his ordinary pursuits for twenty days. Permanent disfiguration of the head or face: The word 'disfigure' in this section means to cause some external injuries which detracts from his appearance, but do not weaken him, e.g., cutting off a man's nose or ears. Branding a girl's cheeks which leaves permanent scars amounts to disfigurement. \"A cut on the bridge of the nose of a girl caused by a sharp weapon like razor or knife has been held to be permanent disfigurement even though the internal wall separating the nostrils was intact'. Grievous hurt is any hurt endangering life which causes imminent danger to life, or causes severe bodily pain for more than 20 days or the hurt caused inability to perform daily routine work for 20 days. (and not for a period of 6 months) Loss of eyesight occurring due to corneal opacity which can be recovered after surgery is a grievous hurt. The gravity of such injury lies in its permanency because it deprives a person of the use of the organ of sight and also disfigures It is a case of Grievous hurt (Sec.320IPC), which is hurt of a more serious nature, although in this case there was no danger to life by the injury but the injury detracts the victim from her appearance, so considered under disfigure.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Disfigure means to cause some external injuries which detracts from his personal appearance, but do not weaken him, e.g., cutting off a man's nose or ears. Option: C. Grievous hurt is any hurt endangering life which causes imminent danger to life; or causing severe bodily pain for more than 20 days or the hurt caused inability to perform daily routine work for 20 days. Option: D. Loss of eyesight occurring due to corneal opacity which can be recovered after surgery is a grievous hurt. The gravity of such injury lies in its permanency because it deprives a person of the use of the organ of sight and also disfigures</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 24-year-old female was living in a joint family with her husband and his relatives. She was married last year only and from then onwards her husband along with his relatives has been consistently torturing her. They used to abuse her verbally and occasionally beat her complaining that she did not bring with her the money and furniture which her father had promised before the marriage. There were scar marks from various injuries over her face and back, she went to her parents and they filed a police complaint against her husband and his relatives. Which of the following statements is correct regarding the case?", "options": [{"label": "A", "text": "Torturing physically and mentally for dowry is punishable under Sec 498A IPC.", "correct": true}, {"label": "B", "text": "This is punishable with imprisonment up to 7 years along with a fine.", "correct": false}, {"label": "C", "text": "Sec. 113A and Sec. 113B IEA deals with presumption as to abduction.", "correct": false}, {"label": "D", "text": "In the case of a dowry-related death, the death of a female occurs within 10 years of her marriage and soon before death she was subjected to cruelty.", "correct": false}], "correct_answer": "A. Torturing physically and mentally for dowry is punishable under Sec 498A IPC.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Torturing physically and mentally for dowry is punishable under Sec 498A IPC. It is a case of torturing both mentally and physically by the husband and his relatives for dowry. In some cases newly married girls are abused, harassed, cruelly treated, and tortured by the husband, in-laws, and their relatives for or in connection with any demand for dowry. In extreme cases, the woman is killed by burning or some other method. Whoever being the husband or the relatives of the husband of the woman, subjects such woman to cruelty shall be punished with imprisonment for a term which may extend to three years and shall also be liable to fine Sec. 498AIPC. Cruelty has been defined as any wilful conduct which drives the woman to commit suicide or grave mental or physical injury to her or harassment of the woman with a view to coerce her for dowry. Presumption as to abetment of suicide by a married woman and presumption as to dowry death is explained under Sec. 113A and Sec. 113B IEA. Where the death of a woman is caused by any burn or bodily injury or occurs otherwise than under normal circumstances within seven years of her marriage. And it is shown that soon before her death she was subjected to cruelty or harassment by her husband or any relative of her husband for, or in connection with, any demand for dowry, such death shall be called \"dowry death\", and such husband or relative shall be deemed to have caused her death. Whoever commits dowry death shall be punished with imprisonment of not less than seven years, but which may extend to life imprisonment sec.304B IPC. Whoever being the husband or the relatives of the husband of the woman, subjects such woman to cruelty as for dowry shall be punished with imprisonment for a term which may extend to three years and shall also be liable to fine Sec. 498AIPC.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. It is punishable with imprisonment for a term which may extend to three years(not 7 years) and shall also be liable to fine Sec. 498AIPC. Option: C. Presumption as to abetment of suicide by a married woman and presumption as to dowry death is explained under Sec. 113A and Sec. 113B IEA. Option: D. Death of a woman is caused by any burn or bodily injury or occurs otherwise than under normal circumstances within seven years (and not 10 years) of her marriage for dowry-related torture, is known as Dowry Death.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You were an intern at the Emergency department of a Govt. hospital, a patient presented there and asked you to sign an application for him stating that he had not been able to do his daily routine work for the last 25 days due to a life-threatening injury caused to him in a fight with his neighbor. You examined him and found that the injury was on his right leg which deliberately impaired his daily routine chores, but you denied signing it as you were not authorized to sign such documents, which of the following statement is correct regarding this type of injury?", "options": [{"label": "A", "text": "If the life of the person is endangered, it is a case of Grievous hurt.", "correct": true}, {"label": "B", "text": "A mere stay of 20 days in the hospital makes the injury Grievous.", "correct": false}, {"label": "C", "text": "Where there is no knowledge that death is likely to be caused by the harm inflicted and death is caused, the accused would be guilty of culpable homicide and not grievous hurt.", "correct": false}, {"label": "D", "text": "Administration of a harmful drug to a person to make him unconscious is Grievous hurt.", "correct": false}], "correct_answer": "A. If the life of the person is endangered, it is a case of Grievous hurt.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>If the life of the person is endangered, it is a case of Grievous hurt. From the given case presentation, it is a type of Grievous hurt as the victim was not able to follow his ordinary pursuits for a period of 20 days or more. Any hurt which endangers life, any hurt which causes the victim to be in severe bodily pain for a period of 20 days, and any hurt which prevents the victim from following his ordinary pursuits for a period of 20 days are classified under Grievous hurt. Any hurt which endangers life: An injury can be said to endanger life if it is itself such that it may put the life of the injured in danger. An injury caused on a vital part of the body cannot be called grievous hurt unless the nature and dimensions of the injury or its effects are such that the doctor is of the opinion that it actually endangers the life of the victim. Administration of a harmful drug to a person to make him unconscious is not grievous hurt, even though in some cases death may be caused if the drug is given in large doses. If the life of the person is not endangered, it is not a case of grievous hurt. To designate an injury as grievous hurt, danger to life should be imminent. Dangerous injuries are those which cause imminent danger to life, either by the involvement of important organs or structures, or extensive area of the body. If no surgical aid is available, such injuries may prove fatal. The concept of injury dangerous to life is not very precise. As such, it is not enough if the medical witness makes a simple statement that the injury in a particular part is dangerous to human life. He should place all relevant data, namely the nature and extent of injury, the kind of weapon used, the part of the body struck, whether the injury caused hemorrhage or shock, affected important structures or organs, or was very extensive, or otherwise caused imminent danger, and should also state the various grounds on which he considers the injury to be a dangerous one. Some examples of injuries that endanger life are: stabs in the abdomen or head or vital part, hurt causing rupture of the squeezing testicles, incised wound on the neck, compound fracture of the skull, rupture of an internal organ, and injury of a large blood vessel. Any hurt which causes the victim to be in severe bodily pain, or unable to follow his ordinary pursuits for a period of 20 days: The length of time during which a sufferer is in pain, disease, or incapacitated from pursuing his ordinary occupation is a defective criterion of the severity of a hurt. It is employed not only in cases where violence has been used but also in cases where hurt has been caused without any assault, e.g., by the administration of drugs, the setting of traps, the digging of pitfalls, the placing of ropes across a road, etc. The extent of the hurt and the intention of the offender are considered for giving punishment. It is difficult to prove that an injured person was in severe bodily pain for 20 days, but it is easier to prove that he was unable to follow his ordinary pursuits due to the hurt. The opinion of the doctor attending to the patient is important, on the point of his disability. A mere stay of 20 days in the hospital does not make injury grievous unless the injured person was in severe bodily pain, or unable to follow his ordinary pursuits for 20 days. Ordinary pursuits include acts of the daily routine of a person, such as eating food, taking bath, going to the toilet, etc. but do not refer to the duties that constitute the job of a person. An injury that endangers life may cause severe bodily pain for 20 days, but an injury that causes such pain may not be dangerous to life, but it is still a grievous hurt under this clause. The line between culpable homicide not amounting to murder and grievous hurt is very thin. In the former, the injuries must be such as are likely to cause death, in the latter the injuries must be such as to endanger life. The likelihood of death resulting from an injury will depend upon the severity of the injury, the structures involved, the age of the individual, and the state of health of the injured. Where there is no intention to cause death, or no knowledge that death is likely to be caused by the harm inflicted and death is caused, the accused would be guilty of grievous hurt if the injury caused was of serious nature, but not of culpable homicide. Any hurt which endangers life, any hurt which causes the victim to be in severe bodily pain for a period of 20 days, and any hurt which prevents the victim from following his ordinary pursuits for a period of 20 days is classified under Grievous hurt.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. A mere stay of 20 days in the hospital does not make injury grievous unless the injured person was in severe bodily pain, or unable to follow his ordinary pursuits for a period of 20 days. Option: C. Where there is no intention to cause death, or no knowledge that death is likely to be caused by the harm inflicted and death is caused, the accused would be guilty of grievous hurt if the injury caused was of serious nature, but not of culpable homicide. Option: D. Administration of a harmful drug to a person to make him unconscious is not grievous hurt, even though in some cases death may be caused if the drug is given in large doses.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 17-year-old girl when returning from her school was stopped in the middle by 2 men, who were constantly harassing her. She refused and asked them to leave her way. They left and returned with a bottle containing acid and tried to throw it on the girl but fortunately, the bystanders attacked them and caught them thus saving the girl. The police were called and an FIR was filed against the men by the parents of the girl. Under which of the following sections of the Indian Penal Code will the criminals be punished now?", "options": [{"label": "A", "text": "Sec. 326B IPC", "correct": true}, {"label": "B", "text": "Sec. 326A IPC", "correct": false}, {"label": "C", "text": "Sec. 333 IPC", "correct": false}, {"label": "D", "text": "Sec. 325 IPC", "correct": false}], "correct_answer": "A. Sec. 326B IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec. 326B IPC This is a case of Acid attack also known as Vitriolage. It is a type of grievous hurt caused voluntarily by the use of acid which causes an imminent threat to the life of the victim. An injury is any harm caused to the body or mind or property or reputation of the victim which includes both simple hurt as well as grievous hurt. Simple hurt (319IPC) is one which is neither extensive nor serious and which heals rapidly whereas Grievous hurt is an injury that can be said to endanger life if it is itself such that it may put the life of the injured in danger defined under 320IPC. There are various acts of the IPC for acid attacks- 326A IPC - It involves voluntarily causing Grievous hurt by the use of acid, which causes severe physical, mental, and financial damage to the victim. It is punishable for not less than 10 years along with a fine. The fine here includes all medical expenses and the sum is collected and given to the victim. 326B IPC - It involves voluntarily throwing or an attempt to throw acid. It is punishable for not less than 5 years. Sec 326 IPC - It involves causing grievous hurt by dangerous weapons or means, here dangerous weapon/means include any instrument for shooting, stabbing or cutting or any instrument, used as a weapon of offence, is likely to cause death; fire or any heated substance; poison, or any corrosive substance which is harmful to the human body to inhale, to swallow, or to receive into the blood or by means of any animal. 326B IPC involves voluntarily throwing or an attempt to throw acid. It is punishable for not less than 5 years.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. 326A IPC involves voluntarily causing Grievous hurt by the use of acid, which causes severe physical, mental and financial damage to the victim. It is punishable for not less than 10 years along with a fine. The fine here includes all medical expenses and the sum is collected and given to the victim. Option: C. 333 IPC is voluntarily causing grievous hurt to prevent a public servant from performing his duty. Here the imprisonment is of 10 years. Option: D. 325IPC is for the punishment for voluntarily causing grievous hurt, punished with imprisonment for a term extending to 7 years and also a fine.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Police arrested an individual for commiting a crime with a teenage girl which caused her face to resemble the one in the image given below. The police presented the man in court and the medical expenses and fine were collected and given to the victim girl. Which of the following sections of the Penal Code is involved in this case?", "options": [{"label": "A", "text": "IPC 326A", "correct": true}, {"label": "B", "text": "IPC 307", "correct": false}, {"label": "C", "text": "IPC 309", "correct": false}, {"label": "D", "text": "IPC 304B", "correct": false}], "correct_answer": "A. IPC 326A", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892804490-QTDF041013IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>IPC 326A It is a case of grievous hurt caused voluntarily by the use of acid also known as Vitriolage. Grievous hurt is severe harm caused illegally to body, mind, or property and is defined under these 8 clauses as:- Clause Kinds of hurt First Emasculation. Second Permanent privation of the sight of either eye. Third Permanent privation of the hearing of either ear. Fourth Privation of any member or joint. Fifth Destruction or permanent impairing of the powers of any member or joint. Sixth Permanent disfiguration of the head or face. Seventh Fracture or dislocation of a bone or tooth. Eighth Any hurt which endangers life, or which causes the sufferer to be during the space of 20 days in severe bodily pain or unable to follow his ordinary pursuits. If it causes permanent disfiguration of the head or face it is included under Grievous hurt, disfiguration means the change of configuration and personal appearance of the subject by some external injury which does not weaken him/her. A person is disfigured when a reasonable observer would find the altered appearance distressing or objectionable. Any hurt which endangers life; causes the victim to be in severe bodily pain for 20 days; unable the victim to follow his ordinary pursuits for a period of 20 days. Any hurt which endangers life means that the life is only endangered and not taken away, i.e. placing a person in danger of death. A mere stay in the hospital for 20 days will not constitute grievous hurt. Ordinary pursuits signify day-to-day personal acts of an individual, like going to the toilet, having food, or taking bath or wearing clothes. It does not include going to work, running, jumping, or driving a vehicle. Dangerous injury has not been defined in the IPC. Dangerous injuries are those which cause imminent danger to life by its direct or imminent effects because of being extensive in nature, involving important structures or organs of the body, and also being likely to prove fatal in absence of medical/surgical aid. Any tear in the dura mater, intracerebral hemorrhages, cerebral edema, laceration of lungs resulting in hemothorax, rupture/perforation of GIT, or any rupture of large arteries/veins are examples of dangerous injuries. Voluntarily causing Grievous hurt by the use of acid, which causes severe physical, mental, and financial damage to the victim. It is punishable for not less than 10 years along with a fine. The fine here includes all medical expenses and the sum is collected and given to the victim, Sec. 326A IPC. Sec.326A IPC involves voluntarily causing grievous hurt by the use of acid, etc. Is punishable with imprisonment of not less than 10 years, but may extend to life, and with a fine. Sec 326B IPC is for voluntarily throwing or attempting to throw acid, imprisonment of not less than 5 years and also fine.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. IPC 307 involves the offence of attempt to murder, when any individual who does any act with intention or knowledge and under such circumstances that it caused death, he would be guilty of murder, and is punished with imprisonment for 10 years, and a Option: C. IPC 309 is involved in the offence of attempt to suicide, earlier it was punished with imprisonment for up to 1 year and with/without fine, now it has been decriminalised by the Government. Option: D. Whoever commits dowry death shall be punished with imprisonment of not less than seven years, but which may extend to life imprisonment sec.304B IPC.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A forensic odontologist was examining a person for identification purposes. He was charting his teeth. Two digits represent a tooth in the charting system of:", "options": [{"label": "A", "text": "Universal system", "correct": false}, {"label": "B", "text": "Palmer’s notation", "correct": false}, {"label": "C", "text": "FDI (Federation Dentaire International) system", "correct": true}, {"label": "D", "text": "Haderup system", "correct": false}], "correct_answer": "C. FDI (Federation Dentaire International) system", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>FDI (Federation Dentaire International) system (Federation Dentaire Internationale) or two-digit System: The Fédération Dentaire Internationale or FDI World Dental Federation notation system is a commonly used system for the numbering and naming of teeth. The system uses a two-number system for the location and naming of each tooth. The jaw is divided into four quadrants between the central incisors and the upper and lower dental arches. The first number refers to the quadrant of a tooth: right upper quadrant = 1, left upper quadrant = 2, left lower quadrant = 3, right lower quadrant = 4 The second number refers to the individual tooth within a specific quadrant: Central incisor = 1, lateral incisor = 2, canine = 3, 1st premolar = 4, 2nd premolar = 5, 1st molar = 6, 2nd molar = 7, 3rd molar = 8 The notation \"21\" would therefore refer to the permanent left upper central incisor.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Hyoid bone fracture is an important finding in the case of throttling where we can find a fracture of the ossified hyoid bone. If the hyoid bone is ossified, the age of the individual is above:", "options": [{"label": "A", "text": "20 Years", "correct": false}, {"label": "B", "text": "30 Years", "correct": false}, {"label": "C", "text": "40 Years", "correct": true}, {"label": "D", "text": "50 Years", "correct": false}], "correct_answer": "C. 40 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>40 Years The greater cornu of the hyoid bone unites with the body between 40 to 60 years. So, if the hyoid bone is ossified, it means to say that age is more than 40 years.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Bertillon system is the method of identification using:", "options": [{"label": "A", "text": "Dental record", "correct": false}, {"label": "B", "text": "Anthropometry", "correct": true}, {"label": "C", "text": "Fingerprints", "correct": false}, {"label": "D", "text": "DNA fingerprinting", "correct": false}], "correct_answer": "B. Anthropometry", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Anthropometry ANTHROPOMETRY (Bertillon system): It is based on the principle that after the age of 21, the dimensions of the skeleton remain unchanged and also that the ratio in size of different parts to one another varies considerably in different individuals. As such, this is applicable only to adults.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A child came to the OPD with his teenage friends with abdominal pain after eating some canned food. For a routine physical examination, a person can give valid consent if he is above:", "options": [{"label": "A", "text": "7 Years", "correct": false}, {"label": "B", "text": "12 Years", "correct": true}, {"label": "C", "text": "16 Years", "correct": false}, {"label": "D", "text": "18 Years", "correct": false}], "correct_answer": "B. 12 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>12 Years A child more than 12 years can give valid consent for a routine physical examination but a child under 12 years cannot give valid consent to suffer any harm that may result from any act done in good faith for the benefit of the child [consent of a guardian or the person having lawful charge of the child is required (89 IPC). Consent given by a person who by reason of immaturity of age (i.e., a child below 12 years) is incapable of understanding the nature and consequences of the act is not valid in the eyes of law (90 IPC).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: D. For any invasive examination and procedure age of consent is >18 years. Options: A & C. - 7 and 16 years have no significance to giving consent for examination.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person who is under the guardianship of a court attains majority at the age of:", "options": [{"label": "A", "text": "16 Years", "correct": false}, {"label": "B", "text": "18 Years", "correct": false}, {"label": "C", "text": "20 Years", "correct": false}, {"label": "D", "text": "21 Years", "correct": true}], "correct_answer": "D. 21 Years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>21 Years Medicolegal implications of age 21:- The qualifying age for the marriage has been prescribed as, “The bride groom should have completed the age of 21 years and the bride, the age of 18 years”—Section 5(iii) HMA. Procuring girl(s) from outside the country or from Jammu and Kashmir for illicit intercourse with another person is punishable under 366-B IPC. For those under the guardianship of court, one is not deemed to attain majority until completion of 21 years of age.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A body was recovered from an abandoned house with stiffening all joints. Which of the following statement is not true regarding the order of appearance of rigor mortis?", "options": [{"label": "A", "text": "It appears first in involuntary muscles", "correct": false}, {"label": "B", "text": "It appears first in the myocardium", "correct": false}, {"label": "C", "text": "It appears in the lower limbs before the upper limbs", "correct": true}, {"label": "D", "text": "It disappears last from the small muscles of the fingers", "correct": false}], "correct_answer": "C. It appears in the lower limbs before the upper limbs", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>It appears in the lower limbs before the upper limbs Rigor mortis usually appears in the upper and lower limbs first. Rigor mortis begins in the eyelids, neck and lower jaw and passes upwards to the muscles of the face, downwards to the muscles of the chest, upper limbs, abdomen and lower limbs and lastly, in the fingers and toes. In individual limbs, it usually progresses from above downwards. Such a sequence is not constant, symmetrical or regular. In individual limbs, it disappears in the same order it has appeared. Rigor mortis always sets in, increases and decreases gradually.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. All other statements about rigor mortis in the given question is correct.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Rigor mortis or cadaveric rigidity is because of the loss of ATP after death. It leads to sustained muscular contraction. False statement about cadaveric rigidity is:", "options": [{"label": "A", "text": "Seen immediately after death", "correct": true}, {"label": "B", "text": "It lasts 18-36 h in summer", "correct": false}, {"label": "C", "text": "It disappears in the sequence as it appears", "correct": false}, {"label": "D", "text": "It last 24- 48 h in winter", "correct": false}], "correct_answer": "A. Seen immediately after death", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Seen immediately after death Rigor mortis is not seen immediately after death. It starts one or two hours after death. Rigor mortis (death stiffening; cadaveric rigidity) is a state of stiffening of muscles, sometimes with slight shortening of the fibres. Individual cell death takes place in this stage. All muscles of the body, both voluntary and involuntary, are affected. It does not start in all muscles simultaneously (Nysten's rule). It first appears _in involuntary muscles; the myocardium becomes rigid in an hour. In India, it begins one to two hours after death and takes another two hours to develop.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: C . In individual limbs, it disappears in the same order in which it has appeared. Rigor mortis always sets in, increases and decreases gradually. Option: B & D. In India, it usually lasts 24 to 48 hours in winter and 18 to 36 hours in summer. It may begin to disappear in about 12 hours. It lasts for 2 to 3 days in temperate regions.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Rigor mortis occurs first in:", "options": [{"label": "A", "text": "Eyelids", "correct": false}, {"label": "B", "text": "Intestines", "correct": false}, {"label": "C", "text": "Myocardium", "correct": true}, {"label": "D", "text": "Neck", "correct": false}], "correct_answer": "C. Myocardium", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Myocardium Rigor mortis first appears in involuntary muscles; the myocardium becomes rigid in an hour. It begins in the eyelids, neck and lower jaw and passes upwards to the muscles of the face, downwards to the muscles of the chest, upper limbs, abdomen and lower limbs and lastly, in the fingers and toes. The lactic acid entered the bloodstream and reconverted to glycogen in the liver. In individual limbs, it usually progresses from above downwards. Such a sequence is not constant, symmetrical or regular. In individual limbs, it disappears in the same order it has appeared. Rigor mortis always sets in, increases and decreases gradually.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Eyelids are the first voluntary muscle to undergo rigor mortis, while the first muscle (including voluntary and involuntary muscles) is the myocardium Option B & D: The intestine and neck are never the first to undergo rigor mortis. Hence these Options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body was recovered from a house in a unique position. The phenomenon shown in the given Image appears first in", "options": [{"label": "A", "text": "Heart", "correct": true}, {"label": "B", "text": "Eyelids", "correct": false}, {"label": "C", "text": "Appears at the same time in the heart and eyelid", "correct": false}, {"label": "D", "text": "Neck", "correct": false}], "correct_answer": "A. Heart", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893434526-QTDF056004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Heart The image demonstrates rigor mortis, appearing first in the heart. The Order of Appearance of Rigor Mortis:- All muscles of the body, both voluntary and involuntary, are affected. It does not start in all muscles simultaneously (Nysten's rule). It first appears in involuntary muscles; the myocardium becomes rigid in an hour. It begins in the eyelids, neck and lower jaw and passes upwards to the muscles of the face, downwards to the muscles of the chest, upper limbs, abdomen and lower limbs and lastly, in the fingers and toes. The lactic acid entered the bloodstream and reconverted to glycogen in the liver. In individual limbs, it usually progresses from above downwards. Such a sequence is not constant, symmetrical or regular. In individual limbs, it disappears in the same order in which it has appeared. Rigor mortis always sets in, increases and decreases gradually.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C and D: Eyelids are the first voluntary muscle to undergo rigor mortis, while the first muscle (including voluntary and involuntary muscles) is the myocardium. The neck undergoes rigor mortis only after the eyelid Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A forensic expert comes to the crime scene and assesses the rigor of the dead body. Which of the following is incorrect about the method of assessment of rigor?", "options": [{"label": "A", "text": "He lifts the eyelids", "correct": false}, {"label": "B", "text": "He taps the glabella", "correct": true}, {"label": "C", "text": "He depresses the jaw", "correct": false}, {"label": "D", "text": "He gently bends the knee joint", "correct": false}], "correct_answer": "B. He taps the glabella", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>He taps the glabella Testing of Rigor mortis: - Rigor is tested by trying to lift the eyelids, depressing the jaw, and gently bending the neck and various joints of the body. Note the degree (absent, minimal, moderate, advanced or complete) and distribution.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, C & D: The other three statements are true ways of testing rigor mortis.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A suicide person was found gripping the gun in his right hand. Which of the following statement about 'cadaveric spasm' is not true?", "options": [{"label": "A", "text": "It appears instantaneously after death", "correct": false}, {"label": "B", "text": "All muscles of the body are involved", "correct": true}, {"label": "C", "text": "Great force is required to overcome it", "correct": false}, {"label": "D", "text": "It indicates the manner of death", "correct": false}], "correct_answer": "B. All muscles of the body are involved", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All muscles of the body are involved The phenomenon doesn't involve all the muscles of the body. It usually is limited to a small group of voluntary muscles. Cadaveric spasm (cataleptic rigidity) is a rare condition. (Option A) In this, the muscles contracted during life become stiff and rigid immediately after death without passing into the stage of primary relaxation. As such, the change preserves the exact attitude of the person at the time of death for several hours afterwards. The spasm is primarily a vital phenomenon that originates from normal nervous stimulation of the muscles. (Option B and D) This is usually limited to a single group of voluntary muscles and frequently involves the hands. Occasionally, the whole body is affected, as seen in soldiers shot in battle, when the body may retain the posture that it assumed at the moment of death. It is not easy to simulate this condition because of the muscles' powerful contraction, which is impossible to recreate artificially.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 60-year-old man presents in OPD with a history of opium addiction for the last 20 yrs. He has given up opium for 2 days. Withdrawal symptoms will include:", "options": [{"label": "A", "text": "Drowsiness", "correct": false}, {"label": "B", "text": "Constricted pupil", "correct": false}, {"label": "C", "text": "Rhinorrhoea", "correct": true}, {"label": "D", "text": "↓ed Blood pressure", "correct": false}], "correct_answer": "C. Rhinorrhoea", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Rhinorrhoea Withdrawal symptoms due to any drug addiction are usually identical, barring minor differences- Chilliness/ sensation of cold, uneasiness, yawning, rhinorrhoea, lacrimation, goose skin, tremors, dilated pupils, anorexia, tachypnoea, ↑ sleep, fever, HT, cramps legs/abdomen, diarrhea.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D: These are signs of opium addiction.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient presented with pinpoint pupil, respiratory depression, and coma. The poisoning is:", "options": [{"label": "A", "text": "Opium", "correct": true}, {"label": "B", "text": "Organophosphate", "correct": false}, {"label": "C", "text": "Dhatura", "correct": false}, {"label": "D", "text": "Organochlorine", "correct": false}], "correct_answer": "A. Opium", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Opium Opium poisoning shows the following features:- Stage of Excitement: There is an increased sense of well-being, increased mental activity, freedom from anxiety, talkativeness, restlessness or even hallucinations, flushing of the face, and a greatly excited or maniacal condition may be seen. Stage of Stupor: The symptoms are headache, nausea, vomiting, incapacity for exertion, a sense of weight in the limbs, giddiness, and drowsiness. The subject lies motionless, with eyes closed as if in a sound sleep from which he may be aroused at first, but soon passes into a stupor and coma. The pupils are contracted, the face and lips are cyanosed and an itching sensation is felt all over the skin. The pulse and respirations are normal. Stage of Coma: The patient passes into a deep coma from which he cannot be roused. The muscles become flaccid and relaxed and all reflexes are abolished. The face is pale, and conjunctivae congested. The pupils are contracted to pinpoint the size and do not react to light but dilate during the agonal asphyxial phase caused by respiratory depression and ultimate paralysis. All the secretions are suspended except sweat. Perspiration is very much increased. The skin is cold and often covered with perspiration. Temperature is subnormal. Blood pressure is low, the pulse slow and full, the breathing is slow and stertorous, and may be reduced to 3 to 4 per minute. The odour of opium may be present in breath.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "All of the following are features of opioid withdrawal EXCEPT:", "options": [{"label": "A", "text": "Seizures", "correct": true}, {"label": "B", "text": "Mydriasis", "correct": false}, {"label": "C", "text": "Insomnia", "correct": false}, {"label": "D", "text": "Hyperventilation", "correct": false}], "correct_answer": "A. Seizures", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Seizures Symptoms of Withdrawal:- Withdrawal symptoms (also referred to as withdrawal reaction or cold turkey), usually the opposite of the acute effects of the drug include nausea and diarrhea, coughing, lacrimation, mydriasis, rhinorrhoea, profuse sweating, muscle twitching, Piloerection (goose bumps) as well as mild elevation in body temperature, respiratory rate, and blood pressure. In addition, diffuse body pain, insomnia, and yawning occur along with intense drug cravings. The intensity of symptoms usually reaches a peak within 36–72 hours after discontinuation of the drug, and the acute syndrome disappears within 5–8 days. However, a protracted abstinence phase of mild symptoms may persist for 6 or more months.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Papaver somniferum milk exudes from?", "options": [{"label": "A", "text": "Leaf", "correct": false}, {"label": "B", "text": "Root", "correct": false}, {"label": "C", "text": "Poppy seed", "correct": false}, {"label": "D", "text": "Unripe capsule", "correct": true}], "correct_answer": "D. Unripe capsule", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Unripe capsule Papavar somniferum/opium:- The unripe capsule is incised and the white juice which exudes is collected and allowed to evaporate to obtain opium. Ripe and dry poppy capsules contain a trace of opium and are used for their sedative and narcotic action. Their warm decoction is used locally as a sedative fomentation and poultice</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following is not a CNS stimulant?", "options": [{"label": "A", "text": "Opioids", "correct": true}, {"label": "B", "text": "TCA", "correct": false}, {"label": "C", "text": "Methylphenidate", "correct": false}, {"label": "D", "text": "Amphetamine", "correct": false}], "correct_answer": "A. Opioids", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Opioids CNS DEPRESSANTS CLASSIFICATION: Ethyl alcohol. General anesthetics. Opioid analgesics. Sedative hypnotics. SEDATIVE-HYPNOTICS: Sedative drugs are those that decrease activity, moderate excitement, and exert a calming effect. A hypnotic drug produces drowsiness and facilitates a state of sleep, resembling natural sleep. CLASSIFICATION: Barbiturates. Benzodiazepines: diazepam, chlordiazepoxide, oxazepam, clorazepate, flurazepam, Lorazepam, temazepam, alprazolam, halazepam, prazepam, triazolam. Nonbarbiturate: paraldehyde. Alcohol, chloral hydrate. Propanediol carbamates: meprobamate, ethinamate. Piperidinediones: glutethimide, methyprylon. Quinazolines: methaqualone.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "An examiner during the final exam asks the second-year student, “ Spanish windlass technique is a type of ?”", "options": [{"label": "A", "text": "Suicidal strangulation", "correct": false}, {"label": "B", "text": "Homicidal strangulation", "correct": true}, {"label": "C", "text": "Both A and B", "correct": false}, {"label": "D", "text": "Accidental strangulation", "correct": false}], "correct_answer": "B. Homicidal strangulation", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Homicidal strangulation HOMICIDAL STRANGULATION : A strangulation is a common form of murder. Many victims are adult women, and strangulation is frequently associated with sexual assault. Usually, there is a single turn of a ligature around the neck, with one or more knots (granny or reef knots) at the front or side of the neck. When there are two or more firm knots, each on separate turns of the ligature, homicide is almost certain. A cord may be tied around the neck, twisted tightly using a stick or some other solid material inserted between the ligature and the skin, and twisted around several times (Spanish Windlass Technique).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Suicidal strangulation: Suicide by strangulation is rare. The victims employ various methods of tightening the ligature. The number of knots, tightness and method of knotting should be considered. The ligature is tightened like a tourniquet, but the person can apply a single or double knot before losing consciousness. In most cases, some mechanical device is always made to keep the ligature tight after insensibility develops. Several turns of rope are tied around the neck with a knot which is usually single and in front or at the side or back of the neck. A running noose is applied to the neck, and the free end of the rope to which a weight is attached is thrown over the end of the bed on which the victim lies. A person may strangle himself by leaning with the whole body weight on a cord passed around the neck and attached to a fixed point. Option: D. Accidental strangulation: Children may get entangled in ropes during play, or the neck may be caught in window cords, etc. Infants are sometimes strangled in their cots when the neck is caught inside bars, in restraints, braces, etc. Occasionally, an infant is strangled with a string attached to a toy tied to the crib. Persons under the influence of alcohol, epileptics, and imbeciles may be strangled by a tight scarf or collar and necktie. It may occur if an intoxicated person rests their neck against a bar or other hard object. It may occur when a string used in suspending a weight on the back slips from across the forehead and compresses the neck.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A gang of three decided to rob a passerby. They decide to attack the victim like is shown below. This is:", "options": [{"label": "A", "text": "Garroting", "correct": false}, {"label": "B", "text": "Mugging", "correct": true}, {"label": "C", "text": "Compression of neck", "correct": false}, {"label": "D", "text": "Smothering", "correct": false}], "correct_answer": "B. Mugging", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892534928-QTDF030002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mugging Strangulation is caused by holding the neck of the victim in the bend of the elbow. The forearm and upper arm exert pressure in front of the larynx or at one or both sides of the neck. The attack is usually made from behind. The postmortem appearances are those of ligature strangulation with a broad object, i.e. the signs are minimal. Sometimes, a diffuse abrasion may be seen along the margin of the jaw due to the friction of the forearm. Internally, there may be diffuse bruising, which may be slight or absent. There may be bruising behind the larynx and in the strap muscles of the neck. Fracture of the superior horn of the thyroid or hyoid is rare. Sometimes, the neck may be pressed by the foot or knee. The larynx and trachea will be crushed when the neck is stamped on repeatedly. And bleeding in the soft tissues with swelling. Death may occur due to asphyxia or reflex cardiac arrest</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. GARROTTING : The victim is attacked from behind without warning. The throat may be grasped, or a ligature is thrown over the neck and quickly tightened, twisting it with a lever (rod, stick, ruler, etc.), within the ligature. The assailant can then tie the ligature with one or more turns. In this way, a single assailant can kill a healthy adult male. This method is usually used in lonely places to kill travellers and rob them. This method had a refinement in which the neck was forced against a sharp spike penetrating the spinal cord. This results in a sudden loss of consciousness and collapse. Garotting as a mode of judicial execution was once employed in Spain. An iron collar around the neck was tightened by a screw for strangling (Spanish Windlass). Option: C. COMPRESSION OF THE NECK : This broad term is used for non-specific causes of neck pressure, which may be sudden. In hard compressions, such as kicking or stamping or jumping on the neck, or karate chops, and flying kicks, soft tissues are grossly damaged. There may be a vertical fracture of the laminae of the thyroid cartilage, cricoid or upper tracheal rings. Hyoid bone and thyroid cartilage tend to be flattened and broken outwards. Death may be rapid with crush injury and seepage of blood into the tissues, or it may be asphyxial due to swelling or airway obstruction. Surgical emphysema may be present. Soft, prolonged neck compression occurs in wrestling, carotid sleeper holds and choke holds. Option: D. SMOTHERING: This is a form of asphyxia caused by closing the external respiratory orifices either by the hand or by other means or blocking up the cavities of the nose and mouth by introducing a foreign substance, such as mud, paper, cloth, etc.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Some unknown person looted a person. He is pretty shaky. Identify the mechanical asphyxia type shown in the Image below.", "options": [{"label": "A", "text": "Garrotting", "correct": false}, {"label": "B", "text": "Bansdola", "correct": false}, {"label": "C", "text": "Mugging", "correct": true}, {"label": "D", "text": "Burking", "correct": false}], "correct_answer": "C. Mugging", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892535069-QTDF030003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mugging MUGGING: Strangulation is caused by holding the neck of the victim in the bend of the elbow. The forearm and upper arm exert pressure in front of the larynx or at one or both sides of the neck. The attack is usually made from behind.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. GARROTTING: The victim is attacked from behind without warning. The throat may be grasped, or a ligature is thrown over the neck and quickly tightened, twisting it with a lever (rod, stick, ruler, etc.), within the ligature. The assailant can then tie the ligature with one or more turns. In this way, a single assailant can kill a healthy adult male. This method is usually used in lonely places to kill travellers and rob them. Option: B. BANSDOLA: One strong bamboo or stick is placed across the back of the neck and another across the front. Both ends are tied with a rope, so the victim is squeezed to death. Option: D. BURKING: Burking is a method of homicidal smothering and traumatic asphyxia. A victim, usually alone or away from the family, was invited to William Burke and William Hare’s house and given alcohol. Then the victim was thrown to the ground, and Burke used to kneel or sit on the chest and close the nose and mouth with his hands, and Hare used to pull him round the room by the feet. Hare turned approver.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Varun is a healthy young man who is grossly intoxicated during a Christmas party. Later, while eating his meal, he suddenly turns blue and cannot breathe. What are you expected to do as first aid if you are at the party and witnessing the situation?", "options": [{"label": "A", "text": "Nothing should be done because he is going to die anyways", "correct": false}, {"label": "B", "text": "Lay him flat on the level ground", "correct": false}, {"label": "C", "text": "Give him water first and a blow on the back till he recovers", "correct": false}, {"label": "D", "text": "Pressure on the abdomen till he recovers", "correct": true}], "correct_answer": "D. Pressure on the abdomen till he recovers", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pressure on the abdomen till he recovers TREATMENT OF CAFE CORONARY: A blow on the back of the sternum may cause coughing and expel the foreign body. If there's difficulty in breathing and cyanosis, first aid is given by application of pressure on the abdomen(Heimlich manoeuvre) till the patient recovers or loses consciousness. If this is unsuccessful, the foreign body should be removed from the hypopharynx with the middle and index fingers or forceps.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B, C :CAFE CORONARY : This is a condition in which a healthy but grossly intoxicated person (restaurant patron), who begins a meal, suddenly turns blue, coughs violently, then collapses and dies without much fuss. Death appears to be due to a sudden heart attack. At autopsy, a large piece of poorly chewed food (bolus or a piece of meat) may obstruct the larynx. The clinical signs of choking are absent because of the high blood alcohol content, which anaesthetises the gag reflex.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A lady was depressed due to divorce. She was in a pub gulping alcohol and eating chicken. Suddenly she collapsed on the floor. In café coronary, the cause of death is:", "options": [{"label": "A", "text": "Asphyxia", "correct": false}, {"label": "B", "text": "Reflex laryngeal spasm", "correct": false}, {"label": "C", "text": "Reflex cardiac arrest", "correct": true}, {"label": "D", "text": "Myocardial Infarction", "correct": false}], "correct_answer": "C. Reflex cardiac arrest", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Reflex cardiac arrest CAFE CORONARY : This is a condition in which a healthy but grossly intoxicated person in the restaurant or pub, who begins a meal, suddenly turns blue, coughs violently, then collapses and dies without much fuss. Death appears to be due to a sudden heart attack. At autopsy, a large piece of poorly chewed food (bolus or a piece of meat) may obstruct the larynx. The clinical signs of choking are absent because of the high blood alcohol content, which anaesthetises the gag reflex.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B & D: Asphyxia, reflex laryngeal spasm and myocardial infarction are not the causes of death in café coronary. Instead, death occurs due to reflex cardiac arrest. Hence these options are not correct.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A depressed person was sitting in a bar. He was eating chicken and gulping alcohol. Suddenly, he collapsed and fell on the floor. Café Coronary is associated with the following:", "options": [{"label": "A", "text": "Myocardial infarction", "correct": false}, {"label": "B", "text": "Hypertension", "correct": false}, {"label": "C", "text": "Choking", "correct": true}, {"label": "D", "text": "Strangulation", "correct": false}], "correct_answer": "C. Choking", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Choking CAFE CORONARY: This is a condition in which a healthy but grossly intoxicated person restaurant patron), begins a meal, suddenly turns blue, coughs violently, then collapses and dies without much fuss. Death appears to be due to a sudden heart attack. At autopsy, a large piece of poorly chewed food (bolus or a piece of meat) may obstruct the larynx. The clinical signs of choking are absent because of the high blood alcohol content, which anaesthetises the gag reflex.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options : A, B & D: Cafe Coronary happens due to blockage of the laryngeal route and has no relation to hypertension, myocardial infarction or strangulation. Hence these options are not correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The type of anoxia which is responsible for the death of a person is shown in the image below", "options": [{"label": "A", "text": "Anemic anoxia", "correct": false}, {"label": "B", "text": "Stagnant anoxia", "correct": false}, {"label": "C", "text": "Histotoxic anoxia", "correct": false}, {"label": "D", "text": "Anoxic anoxia", "correct": true}], "correct_answer": "D. Anoxic anoxia", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892535449-QTDF030008IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Anoxic anoxia Anoxic anoxia: In this type, oxygen cannot reach the blood, because of a lack of oxygen in the lungs. This occurs: From breathing in a contaminated atmosphere, e.g., from exposure to the fumes in wells and tanks or exposure to sewer gas, From mechanical interference with air passage into or down the respiratory tract, e.g., smothering, choking, hanging, strangulation, drowning, traumatic asphyxia and certain forms of acute poisoning.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Anaemic anoxia: In this type, the oxygen-carrying capacity of the blood is reduced, e.g., acute massive haemorrhage, poisoning by carbon monoxide, chlorates, nitrates, and coal tar derivatives. Option: B. Stagnant anoxia: In this type, impaired circulation results in a reduction of oxygen delivery to the tissues, e.g., heart failure, embolism and shock. Option: C. Histotoxic anoxia: In this type, the enzymatic processes by which the tissues use the oxygen in the blood are blocked, e.g., acute cyanide poisoning</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "There’s a fire outbreak in a theatre. Due to some malfunctioning of the emergency exit door, all 150 people had to be evacuated through the main door. In this panic situation, a few people are crushed by the weight of the crowd running towards the door. This is", "options": [{"label": "A", "text": "Traumatic asphyxia", "correct": false}, {"label": "B", "text": "Riot crush", "correct": false}, {"label": "C", "text": "Human pile deaths", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above Traumatic asphyxia results from respiratory arrest due to mechanical fixation of the chest by an unyielding substance or object so that the regular movements of the chest wall are prevented. Fatal cases are only due to accidents. Usually, there is a gross compression of the chest and usually the abdomen by a powerful force, which prevents chest expansion and diaphragmatic lowering. Causes: Multiple deaths are likely to occur when there is an outbreak of fire in a theatre or whenever large crowds gather in an enclosed place. The weight of the crowd crushes some, the chest being pressed violently, or may even get trampled on and crushed under feet (riot crush or human pile deaths). Another common cause is crushing by falls of earth or stone, usually in a coal mine, during tunnelling, or in a building collapse, even if the head remains above the fallen soil. Similarly, burial in grain, sand, coal or mineral may have the same effect. Sometimes, the victim is pressed to the ground by some heavyweight as a motor vehicle or other machinery. A person repairing a car may be crushed when the jack slips, and the vehicle falls on top of him. It may occur in assault cases, where the victim is jumped, stamped upon, and crushed by one or more assailants. It occurs in industrial disasters, earthquakes and landslides. Occasionally, it results from indirect compression, when the body is subjected to force so that his thighs and the knees are driven against his chest, the so-called \"jack-knife\" position.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Arun comes to meet his friend Nakul at home. Arun finds something suspicious because Nakul neither answers his call nor opens the door. He immediately calls up the police. The police break opens the door and notices a weird setup in his room. They see the dead man wearing female clothes and are found hanging from the fan. They could not conclude if it were a homicide or suicide from the scene. On interrogating the dead man’s friend, he says that Nakul and himself are homosexual. The whole scenario is dealing with.", "options": [{"label": "A", "text": "Sexual asphyxia", "correct": false}, {"label": "B", "text": "Autoerotic asphyxia", "correct": false}, {"label": "C", "text": "Asphyxiophilia", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above Sexual asphyxias (autoerotic asphyxia; Asphyxiophilia) are very rare. Partial asphyxia caused by pressure on carotid vessels or partial obstruction of air passages causes cerebral disturbances and may lead to hallucinations of an erotic nature in some men. The degree of asphyxia produced by mechanical means is controlled, but in some cases, death occurs accidentally. These cases are associated with some form of abnormal sexual behaviour. Usually, masochism and transvestism. The victims are almost always males and usually young. The scene is usually the victim's house; the bedroom, bathroom, basement or attic are usually selected, and the door is locked inside. Adult males with homosexual preferences tend to carry out the procedure in pairs as a means of protection from accidental death. Methods: Hanging is the most frequent form seen in sexual asphyxias.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following is a positive finding in the case of traumatic asphyxia?", "options": [{"label": "A", "text": "Fracture of the hyoid bone", "correct": false}, {"label": "B", "text": "Fracture of thyroid bone", "correct": false}, {"label": "C", "text": "Crescentic nail marks on the neck", "correct": false}, {"label": "D", "text": "Upper half of body- congested while lower half normal", "correct": true}], "correct_answer": "D. Upper half of body- congested while lower half normal", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Upper half of body- congested while lower half normal A positive finding in a case of traumatic asphyxia:- The prominent feature is the intense congestion, petechial and confluent haemorrhages and cyanosis of deep purple or purple-red colour of the head, neck, and upper chest above the compression level.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A & B. Fractures of the hyoid and thyroid are seen in strangulation and also in hanging. It is not seen in traumatic asphyxia usually. Option: C. Crescentic nail marks on the neck are seen in cases of manual strangulation and not in traumatic asphyxia.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A poison that is illuminous, translucent, and waxy?", "options": [{"label": "A", "text": "Lodine", "correct": false}, {"label": "B", "text": "Ammonium bromide", "correct": false}, {"label": "C", "text": "Cobra venom", "correct": false}, {"label": "D", "text": "Yellow phosphorus", "correct": true}], "correct_answer": "D. Yellow phosphorus", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Yellow phosphorus White or yellow phosphorus: - It is used in fertilizers, insecticides, rodenticides, incendiary bombs, smoke screens, fireworks, etc. It is a translucent waxy cylinder. Smells and tastes garlicky.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which among the following is a waxy, luminous & translucent poison?", "options": [{"label": "A", "text": "Yellow phosphorus", "correct": true}, {"label": "B", "text": "Cobra venom", "correct": false}, {"label": "C", "text": "Organophosphates", "correct": false}, {"label": "D", "text": "Iodine", "correct": false}], "correct_answer": "A. Yellow phosphorus", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Yellow phosphorus YELLOW/WHITE PHOSPHORUS Colour:-White or yellow Appearance: Translucent, waxy cylinders. Smell:-Garlicky</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "On opening the body of a poisoning victim Yellow Fatty Liver was found. This is caused by which of the following poisonings?", "options": [{"label": "A", "text": "Phosphorus", "correct": true}, {"label": "B", "text": "Arsenic", "correct": false}, {"label": "C", "text": "Lead", "correct": false}, {"label": "D", "text": "Mercury", "correct": false}], "correct_answer": "A. Phosphorus", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Phosphorus Autopsy findings in phosphorus poisoning. External: Emaciation, purpuric rashes, jaundice, garlicky smell The mucous membrane of the mouth is corroded Dark brown colored hypostasis Internal: Multiple hemorrhages in muscles, mucosa, serosa GIT, RS, liver, kidney, heart, peritoneum, lungs, brain Stomach and intestines - mucous membranes: yellowish or greyish-white, softened, thickened, inflamed, corroded in patches; stomach contents - luminous, garlicky smell Liver - swollen, yellow, soft, fatty, friable Kidneys - enlarged, greasy, yellow 5. Heart - flabby, pale, shows fatty degeneration 6. Lungs - fat emboli in pulmonary arterioles, and capillaries.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B . Arsenic poisoning—Substances used are As2O3, Arsenic trioxide, Arsenious oxide, Scheele’s green, Paris green/Emerald green, Arsine gas, Orpiment/Realgar. ‘sankhya=somalkhar’ Arsenic poisoning is of three types:- Fulminant—Death in 3 hrs. Gastroenteric—most common, resembles bacterial food poisoning; constriction of the throat, colicky pain, intense thirst, vomiting, uremia, circulatory collapse. Chronic—Rash, hyperkeratosis, rain-drop pigmentation, basal cell carcinoma, cirrhosis of the liver, portal hypertension, subendocardial petechial hemorrhages of the heart. Tests for diagnosis are—Marsh’s test and Reinsch’s test. Option: C. Lead poisoning: Symptoms include- metallic taste -abdominal pain - constipation or diarrhea (black stool) - vomiting -hyperactivity or lethargy - ataxia - behavioral changes - convulsions CHRONIC POISONING: Myalgia Paraesthesia Fatigue Irritability Abdominal discomfort Arthralgia Muscular exhaustibility Tremor Headache Diffuse abdominal pain Anorexia, metallic taste, vomiting Constipation Weight loss Hypertension Lead palsy: wrist or foot drop A bluish-black lead line on gums Lead colic: severe abdominal cramps. Lead encephalopathy. Option: D . Mercury poisoning: The signs and symptoms start immediately after swallowing the poison: Acrid metallic taste in the The feeling of constriction or choking of the Hoarseness of voice, there is difficulty in breathing, and mouth and tongue are corroded and swollen with grey white coating. Hot burning pain in mouth, stomach, and abdomen. Stools are blood-stained, urine is suppressed and scanty, contain blood, and albumin is accompanied by necrosis of renal tubules and damage to the glomeruli. Pulse is quick small and irregular, there is a circulatory failure. Thrombocytopenia and bone marrow depression. When injected intravenously, it produces dyspnoea, cyanosis, hypotension, and convulsions, death may be due to an anaphylactic shock or ventricular fibrillation. After 1-3 days- renal tubular necrosis l/t polyuria, albuminuria, uremia, and acidosis, and in GIT membranous colitis l/t dysentery may develop.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient is admitted with acute organophosphorus insecticide poisoning, develops ptosis, inability to lift the head, and difficulty in respiration on the third day of the poisoning. The most likely diagnosis is", "options": [{"label": "A", "text": "Hypokalemia", "correct": false}, {"label": "B", "text": "Intermediate syndrome", "correct": true}, {"label": "C", "text": "Delayed syndrome", "correct": false}, {"label": "D", "text": "Polymyositis", "correct": false}], "correct_answer": "B. Intermediate syndrome", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Intermediate syndrome In some cases of OP poisoning, after one to four days muscle weakness and paralysis Characterised by motor cranial nerve palsies, weakness of neck flexor and proximal limb muscles, and acute respiratory paresis are seen due to prolonged cholinesterase inhibition and muscle necrosis. It does not respond to oximes or atropine.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 45 years old male working in a factory presented to the OPD of a hospital with complaints of swelling of the lower jaw which started after the complaints of a toothache, there was the loosening of the teeth along with necrosis of gums. He revealed a history of a missing tooth in the lower jaw. On taking proper history he revealed symptoms like nausea, vomiting, anorexia, loss of weight, and jaundice-like symptoms. On stool sampling, it smelled of a garlicky smell. Which of the following substance caused this poisoning?", "options": [{"label": "A", "text": "Phosphorus Poisoning", "correct": true}, {"label": "B", "text": "Arsenic Poisoning", "correct": false}, {"label": "C", "text": "Mercury Poisoning", "correct": false}, {"label": "D", "text": "Lead Poisoning", "correct": false}], "correct_answer": "A. Phosphorus Poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Phosphorus Poisoning The features mentioned in the case indicates it to be a case of Chronic phosphorus poisoning. There are 2 varieties of Phosphorus - White/ Yellow and Red Phosphorus. White phosphorus is used in fertilizers, rodenticides, fireworks, gunpowder, etc. While Red phosphorus is used on the sides of a matchbox. In the case of chronic poisoning, there is a frequent inhalation of fumes over a period of years causing necrosis of the lower jaw in the region of a decayed tooth. The vapors act on the jaw through a carious tooth or an interspace due to a missing tooth where suppurative microorganisms are already present. At first there is a toothache, which is followed by swelling of the jaw, loosening of the teeth, necrosis of gums, and sequestration of bone in the mandible. It is known as “Phossy Jaw” (glassy jaw) in which osteomyelitis and necrosis of the jaw occur, with multiple sinuses discharging foul-smelling Its systemic symptoms include - Nausea, Vomiting, Anorexia, Pain in the stomach, Indigestion, purging, pain in the joints, loss of weight, bronchitis, jaundice, and anemia. The fatal dose for Phosphorus poisoning is 60-120mg. The treatment includes Gastric lavage using a 1:5000 solution of Potassium permanganate which causes the oxidation of phosphorus into phosphoric acid and phosphates, which are harmless. Stomach wash with activated charcoal, 0.2% CuSO4 solution until vomiting occurs is done. Vit. K (20mg), i.v. in repeated doses to combat hypoprothrombinemia, or blood transfusion is given. Phosphorus Poisoning - Phossy Jaw, i.e, chronic osteomyelitis of mandible with multiple sinuses discharging foul-smelling fluid/ pus. The disease is obsolete now as safety matches are used which are made of Potassium chlorate, Antimony sulfide.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Arsenic Poisoning - Chronic Arsenic poisoning causes, hyperkeratosis of palms and soles, brown mottled patches over eyelids, forehead, and temple, and rashes resembling measles are seen. Sub-endocardial hemorrhages of ventricles were seen only in 4 poisons- Arsenic, Phosphorus, Mercury, and Viper Snake Bite. Option: C. Mercury Poisoning - It inhibits the sulphydryl group of mitochondrial enzymes. Chronic mercury poisoning is called Hydrargyrism, characterized by a classical triad of- Gingivostomatitis, Mercurial tremors, and mercurial erethism. The characteristic finding of Mercuria lentis (deposition of mercury in anterior lens capsule gives malt brown reflex on slit lamp examination) is seen. Option: D. Lead Poisoning - Metallic lead is poisonous, Chronic lead poisoning is called Plumbism/ Saturnism. The characteristic features of Lead poisoning include Circumoral facial pallor, microcytic hypochromic anemia, eosinophilia, Burtonian lines (seen at the junction of teeth and gums, in those teeth that are infected/ caries because of decomposition of food, H2S is formed), lead palsy and lead encephalopathy.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 3-year-old child was brought to the Emergency Department with complaints of nausea, vomiting, diarrhea, and a garlicky smell of breath and vomitus. A history of ingestion of rat paste by the child was given. You as the duty doctor at that time, assessed it as a case of poisoning, what are the differentiating features of white phosphorus which helped you to distinguish it from its other variety, red phosphorus?", "options": [{"label": "A", "text": "White phosphorus is non-luminous in dark.", "correct": false}, {"label": "B", "text": "White phosphorus is an amorphous, solid mass.", "correct": false}, {"label": "C", "text": "White phosphorus occurs as soft, scaly crystals and has a metallic luster and an unpleasant taste.", "correct": false}, {"label": "D", "text": "White phosphorus oxidizes and emits white fumes, ignites at 34 degrees and so is kept under water.", "correct": true}], "correct_answer": "D. White phosphorus oxidizes and emits white fumes, ignites at 34 degrees and so is kept under water.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>White phosphorus oxidizes and emits white fumes, ignites at 34 degrees and so is kept under water. The garlicky smell of breath and vomitus along with the clinical features and the history of ingestion of rat paste indicates a case of Phosphorus poisoning. The 2 varieties of phosphorus are – White (crystalline, used in fertilizers, insecticides, rodenticides, etc.) and Red (amorphous and non- toxic). White phosphorus is a protoplasmic poison, which affects cellular oxidation. Fatal dose- 60 to 120mg; fatal period- 2 to 8 days. There are 3 types of poisoning in this case: 1. Fulminating poison- when more than 1g poison is ingested, patients usually die within 12 hrs due to shock and cardiovascular collapse because phosphorus has a direct action on the heart and blood vessels. Those who survive more than 12 hrs are restless, delirious and some maniacal before death. Symptoms like thirst, severe nausea, vomiting, and retching occur. Acute poison- It occurs in 3 stages. Due to local irritation, symptoms occur within a few minutes to a few hrs after exposure and last from 8 hrs to 3 days. Ingestion produces burning pain in the throat and abdomen, with intense thirst, nausea, vomiting, diarrhea, and severe abdominal pain. The 2nd stage is the symptom-free period lasting for 2-3 days. Red phosphorus is Reddish brown in color, an amorphous solid mass. It is odorless, tasteless, and non-luminous in the dark. On exposure to air, it is non-oxidized, non-fuming, and non-inflammable. It is found on the sides of matchboxes. Treatment includes Gastric lavage (1:5000 KMnO4 which oxides phosphorus into phosphoric acid and phosphates, which are harmless; Stomach washes with activated charcoal and 0.2% Copper Sulphate solution); Vitamin K 20mg, i.v., in repeated doses to combat hypoprothrombinaemia or blood transfusion; Bowel should be evacuated with Magnesium sulfate. S.NO. Trait White phosphorus Red phosphorus (1) Colour: White or yellow. Reddish-brown (2) Appearance: Translucent, waxy cylinders. Amorphous, solid mass. (3) Smell: Garlicky. Odourless. (4) Taste: Garlicky. Tasteless. (5) Luminosity: Luminous in the dark. Non-luminous. (6) Exposure to air: Oxidises and emits white fumes; ignites at 34°C. and as such kept underwater. Non-oxidized, non-fuming. non-inflammable. (7) Use Fertilisers, and vermin-killers, rodenticide, fireworks, gunpowder, etc. On the sides of a matchbox. (8) Toxicity: Highly toxic. Non-toxic.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. White phosphorus causes vomitus and excreta to be luminescent known as Smoky stool syndrome, it is a diagnostic feature along with the Garlicky smell of the breath, vomitus, and excreta. Option B. White phosphorus is white or yellow in color and is translucent and as waxy cylinders, it causes fatty degeneration of the liver with some cellular necrosis, and small hemorrhages on the surface and in the substance. Option C . Iodine occurs as bluish-black, soft, and scaly crystals and has a metallic luster and an unpleasant taste, it gives off a violet-colored vapor at all temperatures, which has a characteristic odor.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An MLC report was made in the case of the poisoning of a 48-year-old male who fell unwell at his house, on bringing him to the hospital he was declared brought dead by the duty doctor. The symptoms of the patient resembled acute liver disease. He complained of irritation and burning pain in the throat and abdomen, with intense thirst, nausea, vomiting, diarrhea, and severe abdominal pain. He gave the history of drinking coffee this morning with his client at his office. Breath and excreta had a garlicky smell. Which of the following correctly matches the treatment options to be done for this poisoning case?", "options": [{"label": "A", "text": "Gastric lavage with 1:10000 solution of KMnO4 and activated charcoal.", "correct": false}, {"label": "B", "text": "0.2% CuSO4 solution is used to wash the stomach and is the chemical antidote for this poisoning.", "correct": true}, {"label": "C", "text": "Vit. E, 20mg, i.v. in repeated doses to combat hypoprothrombinaemia or blood transfusion.", "correct": false}, {"label": "D", "text": "Oils and fats should be used as they decrease the absorption of the poison.", "correct": false}], "correct_answer": "B. 0.2% CuSO4 solution is used to wash the stomach and is the chemical antidote for this poisoning.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>0.2% CuSO4 solution is used to wash the stomach and is the chemical antidote for this poisoning. It is a case of Acute Phosphorus Poisoning which is accidentally poisoned by children due to chewing fireworks or by eating rat pastes; occasionally used for homicide mixed with alcohol, coffee, etc. There is a delay in the appearance of symptoms, and it resembled acute liver disease. Fatal dose - 60 to 120 mg; fatal period- 2 to 8 days. Treatment- Gastric lavage using a 1:5000 solution of Potassium permanganate which oxidizes phosphorus into phosphoric acid and phosphates, which are harmless. Activated charcoal adsorbs the poison. Stomach can be washed with 0.2% copper sulfate solution or 0.2g of Copper sulfate may be given every 5 minutes until vomiting occurs. It coats the particles of phosphorus with a film of copper phosphide which is relatively harmless. As it has caustic properties and can cause acute copper poisoning care should be taken. Vit K (20mg) i.v., in repeated doses to combat hypoprothrombinaemia or blood transfusion. The bowel should be evacuated with magnesium sulfate. Wash out the bowel and repeat at intervals for several days. Oils and fats should be avoided as they dissolve phosphorus and promote absorption. Transfusion of glucose-saline and plasma with vitamins and nor- adrenaline is useful to protect the liver and to correct shock and dehydration. If renal failure is severe, peritoneal or hemodialysis may be required Burns should be thoroughly washed with one percent copper sulfate solution in water.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Gastric lavage using a 1:5000 solution of Potassium permanganate which oxidizes phosphorus into phosphoric acid and phosphates, which are harmless is the correct option to treat the poisoning of phosphorus. Option: C. Vit K (20mg) i.v., in repeated doses to combat hypoprothrombinaemia or blood transfusion is the correct option for vitamin replacement. Option: D. Oils and fats should be avoided as they dissolve phosphorus and promote absorption and hence should not be used in case of phosphorus poisoning.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A female was came to the Emergency Department with complaints of flapping tremors, hemorrhage into the skin, mucous membrane, and hematuria along with symptoms like nausea, vomiting, pain abdomen, etc. She died and on autopsy, it was revealed that the esophagus, stomach, and intestines had signs of irritation along with the presence of some luminous material in the stomach. The gastric and intestinal contents smelled garlicky and were luminous, their mucous membrane was yellowish in color. Signs of liver disease were noticed, which among the following correctly matches the stages of this poisoning? In the first stage due to local irritation symptoms like a burning pain in throat and abdomen are seen. The second stage is a symptom-free period lasting 2-3 days. Skin contact produces hard nodule-like structures. In the third stage, symptoms of systemic toxicity occur from absorbed poison. CNS involvement is not present in this poisoning. Excreta do not have the garlicky smell as presented by the vomitus and breath. Select the correct answer from given below code:-", "options": [{"label": "A", "text": "1,2,4", "correct": true}, {"label": "B", "text": "2,3,4", "correct": false}, {"label": "C", "text": "3,4,5", "correct": false}, {"label": "D", "text": "1,5,6", "correct": false}], "correct_answer": "A. 1,2,4", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,2,4 It is a case of Acute Phosphorus Poisoning indicated by the clinical features mentioned above and by the PM findings. Acute poisoning occurs in 3 stages. First Stage - Due to local irritation, symptoms occur within a few minutes to a few hours after exposure and last from 8 hrs to 3 days. Ingestion produces burning pain in the throat and abdomen, with intense thirst, nausea, vomiting, diarrhea, and severe abdominal pain. Breath and excreta have a garlic-like odor. Luminescent vomit and faeces are diagnostic. Skin contact produces painful penetrating second and third-degree burns which heal slowly. Second Stage - It is a symptom-free period lasting for 2-3 days. Third Stage - Symptoms of systemic toxicity occur from absorbed poison. There is nausea, vomiting, diarrhea, hematemesis, liver tenderness, enlargement, jaundice, and pruritis. Hemorrhages occur in the skin, mucous membrane, and viscera, due to injury of blood vessels and inhibition of blood clotting. Renal damage results in oliguria, haematuria, casts, albuminuria, and sometimes anuria. Involvement of CNS causes convulsions, delirium, and coma. If the patient survives, symptoms may persist for a long time. Death may result from shock, hepatic failure, CNS damage, haematemesis, or renal insufficiency. Treatment includes - Gastric lavage (KMnO4 + CuSO4 + activated charcoal) and i.v. Vit. K. 1,2,4 are the correct options as in the first stage due to local irritation symptoms like a burning pain in the throat and abdomen are seen; the second stage is a symptom-free period lasting for 2-3 days and in the third stage, symptoms of systemic toxicity occur from absorbed poison.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Skin contact produces painful penetrating second and third-degree burns which heal slowly so it is not the correct answer as it has been wrongly matched. Option: C. Involvement of CNS causes convulsions, delirium, and coma and if the patient survives, symptoms may persist for a long time. Death may result from shock, hepatic failure, CNS damage, haematemesis, or renal insufficiency also skin contact produces painful penetrating second and third-degree. Option: D. Involvement of CNS causes convulsions, delirium, and coma and if the patient survives, symptoms may persist for a long time, and breath and excreta have a garlic-like odor. Luminescent vomit and faeces are diagnostic.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A poisoning case was reported after the victim succumbed to death following the ingestion of the substance as shown in the given image, his autopsy report showed the following findings, emaciation, purpuric hemorrhages in the skin, jaundice, and garlicky odor. The mucous membrane of the mouth was eroded, and hypostasis is dark brown in color. Internal findings were multiple hemorrhages seen in the muscles, serosal and mucous membranes of GIT, flabby and pale heart showing fatty degeneration. Which poison is this?", "options": [{"label": "A", "text": "Phosphorus", "correct": true}, {"label": "B", "text": "Cadmium", "correct": false}, {"label": "C", "text": "Copper", "correct": false}, {"label": "D", "text": "Lead", "correct": false}], "correct_answer": "A. Phosphorus", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893976508-QTDF075009IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Phosphorus It is given Phosphorus which oxides on exposure to air, so stored under water. The findings of the autopsy also revealed it to the be a case of Phosphorus Poisoning. Phosphorus exists in two varieties- White or crystalline: Samples of white phosphorus always contain some red phosphorus and therefore appear yellow also called ‘yellow phosphorus’. Red or amorphous: White gradually changes to red phosphorus. This transformation is accelerated by heat and light. It is a protoplasmic poison and affects cellular oxidation. The metabolism of cells reduces, leading to necrobiosis which is predominantly seen in the White phosphorus causes painful penetrating second to third-degree burn injuries. It typically appears as a necrotic area with a yellowish color and a characteristic garlicky odor. It is lipid soluble and hence results in rapid dermal penetration and delayed wound healing. PM findings:- External Emaciation, purpuric hemorrhages in the skin, jaundice, and smell of garlic may be present.\" The mucous membrane of the mouth is corroded. Hypostasis is dark brown in color.3 Internal Multiple hemorrhages are seen in the muscles, serosal and mucosal membranes of the GIT and respiratory tract, liver, kidneys, endocardium, pericardium, epicardium, peritoneum, lungs, and brain. Stomach and intestines: Mucous membranes are yellowish or grayish-white in color, softened, thickened, inflamed, and corroded in patches; luminous material may be found in the stomach. Contents may smell of garlic. Liver: Swollen, yellow, soft, fatty, and easily ruptured.* Kidneys: Enlarged, greasy, yellow. Heart: Flabby, pale, and shows fatty degeneration. Lungs: Fat emboli may be found in the pulmonary arterioles and capillaries. Treatment includes - Gastric lavage using a 1:5000 solution of Potassium permanganate which oxidizes phosphorus into phosphoric acid and phosphates, which are harmless is the correct option to treat for the poisoning of phosphorus. The stomach can be washed with 0.2% copper sulfate solution or 0.2g of Copper sulfate may be given every 5 minutes until vomiting occurs. It coats the particles of phosphorus with a film of copper phosphide which is relatively harmless. As it has caustic properties and can cause acute copper poisoning care should be taken. Vit K (20mg) i.v. in repeated doses to combat hypoprothrombinaemia or blood transfusion is the correct option for vitamin replacement. It is a case of phosphorus poisoning as the image and the autopsy findings suggest of it. It has hemorrhagic syndrome along with hepatotoxicity and the features of luminescence and garlicky odor of excreta, vomitus, and intestinal contents.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Cadmium is a soft, white metal, used in welding, metal plating, battery, and plastic industries. Poisoning may occur from the inhalation of cadmium dust or fumes or from the ingestion of cadmium PM findings show pulmonary edema and emphysema. There may be degeneration and/or loss of bronchial and bronchiolar epithelial cells. Option: C. Copper causes greenish-blue discoloration of vomitus and skin due to the fumes of copper. PM changes include froth and gastric contents turning greenish-blue. Green lines on gums. Chalcosis is the condition of presence of copper deposits in tissues. Option: D . Metallic lead is poisonous, Chronic lead poisoning is called Plumbism/Saturnism. The characteristic features of Lead poisoning includes Circumoral facial pallor, microcytic hypochromic anemia, eosinophilia, and Burtonian lines seen at the junction of teeth and gums.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 19 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Post-mortem hypostasis is caused due to:", "options": [{"label": "A", "text": "Hemolysis of the red cells, which stains the walls of the blood vessel", "correct": false}, {"label": "B", "text": "Capillo-venous distension from gravitational pooling of blood", "correct": true}, {"label": "C", "text": "Infiltration of blood under the skin due to Haemolysis", "correct": false}, {"label": "D", "text": "Rupture of vessels and extravasation of blood", "correct": false}], "correct_answer": "B. Capillo-venous distension from gravitational pooling of blood", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Capillo-venous distension from gravitational pooling of blood MECHANISM OF POST-MORTEM HYPOSTASIS Mechanism: The stoppage of circulation causes the stagnation of blood in blood vessels and its tendency to sink by the force of gravity. The blood tends to accumulate in the toneless capillaries and venules of the dependent parts of the body. The filling of these vessels produces a bluish-purple colour on the adjacent skin. The upper portions of the body drained of blood are pale. The intensity of the colour depends upon the amount of reduced haemoglobin in the blood. In cases of a large amount of reduced haemoglobin before death, the blood has deep purplish-red colour. The colour of the hypostasis may vary from area to area in the same body.</p>\n<p><strong>Random:</strong></p><p>Explanation For incorrect Option:- Option: A, C & D. Since postmortem hypostasis occurs due to capillo-venous distention from the gravitational pooling of blood, other explanations in the options are irrelevant in this context. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Post-mortem hypostasis is unlikely to develop in the case of:", "options": [{"label": "A", "text": "Post-mortem drowning", "correct": false}, {"label": "B", "text": "Drowning in cold water", "correct": false}, {"label": "C", "text": "Drowning in seawater", "correct": false}, {"label": "D", "text": "Drowning in a fast-flowing river", "correct": true}], "correct_answer": "D. Drowning in a fast-flowing river", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Drowning in a fast-flowing river In case of drowning, post-mortem staining is usually found on the face, the upper part of the chest, hands, lower arms, feet and lower legs because in still water, when the body floats, the abdomen is lighter in weight due to accumulation of gases remains at a higher level than the head and shoulders, which are heavier. The limbs will be hanging passively. This explains the distribution of postmortem staining in the described areas. If the body is constantly changing due to forceful currents/waves of water and in a fast-moving water body where the body's position is constantly changing, staining may not develop.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C . Postmortem Hypostasis is seen in postmortem drowning and drowning in cold or seawater. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which enzyme has the maximum role in putrefaction?", "options": [{"label": "A", "text": "Lipase", "correct": false}, {"label": "B", "text": "Trypsin", "correct": false}, {"label": "C", "text": "Acetylcholine esterase", "correct": false}, {"label": "D", "text": "Lecithinase", "correct": true}], "correct_answer": "D. Lecithinase", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lecithinase Lecithinase produced by Cl. welchii is most important in putrefaction. This hydrolyses the lecithin in all cell membranes, including blood cells·, and is responsible for the post-mortem haemolysis of blood.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C . Lipase, Trypsin and acetylcholine esterase do not have much role in putrefaction and postmortem hemolysis. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body was taken for autopsy just after death in the emergency. There was no lividity over the body. Post-mortem lividity is usually easy for anybody to see after about:", "options": [{"label": "A", "text": "30 minutes", "correct": false}, {"label": "B", "text": "3 hours", "correct": true}, {"label": "C", "text": "12 hours", "correct": false}, {"label": "D", "text": "24 hours", "correct": false}], "correct_answer": "B. 3 hours", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>12 hours Postmortem lividity begins shortly after death. However, it may not be visible for about half to one hour after death in normal individuals and from about one to four hours in anaemic persons. Dull-red patches of 1 to 2 cm. diameter appears in 20 to 30 minutes to two hours. These patches then deepen, increase in intensity and become confluent in one to 4 hours. In the early stage, these patches can be mistaken for bruises. In doubtful cases, a portion should be removed for microscopic examination.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D . Since postmortem lividity is seen in 3 hours, other timeframes in the options are insignificant in this context. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The body of a person was found lying in a forest. It seems it was lying there for some time as it started decomposing. In a decomposed body, the first sign seen is:", "options": [{"label": "A", "text": "Greenish dislocation of skin over right iliac fossa", "correct": true}, {"label": "B", "text": "Greenish dislocation of skin over left iliac fossa", "correct": false}, {"label": "C", "text": "Purplish black dislocation on the face", "correct": false}, {"label": "D", "text": "Purplish black dislocation over lower extremity", "correct": false}], "correct_answer": "A. Greenish dislocation of skin over right iliac fossa", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Greenish dislocation of skin over right iliac fossa The first external sign of putrefaction in a body lying in the air is usually a greenish discolouration of the skin over the region of the caecum, which lies fairly superficially, and where the contents of the bowel are more fluid and full of bacteria.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C & D . All the other findings mentioned in the options occur after the greenish discolouration of the skin over the right iliac fossa. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A body has dark brown post-mortem staining and garlic odour in the stomach during autopsy. The most likely poison is:", "options": [{"label": "A", "text": "HCN", "correct": false}, {"label": "B", "text": "Hydrogen sulphide", "correct": false}, {"label": "C", "text": "Phosphorous", "correct": true}, {"label": "D", "text": "CO2", "correct": false}], "correct_answer": "C. Phosphorous", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Phosphorous Post Mortem Appearances of phosphorus poisoning: The oesophagus, stomach and intestines may show signs of irritation, and the stomach may have luminous material. In acute poisoning, the body usually shows signs of jaundice. The gastric and intestinal contents may smell of garlic and be luminous. The mucous membranes of the stomach and intestine are yellowish or greyish-white and softened, thickened, inflamed and corroded or destroyed in patches. Multiple smaller or larger haemorrhages are seen in the skin, subcutaneous tissues, muscles, and serosal and mucosal membranes of the gastrointestinal and respiratory tract, under the endocardium, pericardium, epicardium, peritoneum, in lungs, brain, leptomeninges and uterus. The liver becomes swollen, yellow, soft, and fatty and is easily ruptured. Small haemorrhages may be seen on the surface and in the substance. In persons who survive for a week or longer, the appearances of acute yellow atrophy are present. The kidneys are large, greasy, and yellow and show haemorrhages on the surface. The heart is flabby and pale and shows fatty degeneration. Fat emboli may be found in the pulmonary arterioles and capillaries. The blood may appear tarry, and its coagulability is diminished.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D. Cyanide poisoning, hydrogen sulphide poisoning or carbon dioxide poisoning does not show dark brown post-mortem staining or garlic odour in the stomach. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Statement: Dull-red patches of 1 to 2 cm. diameter appears in 20 to 30 minutes to two hours. These patches then deepen, increase in intensity and become confluent in one to 4 hours. In the early stage, these patches can be mistaken for bruises. Development of what postmortem change is being mentioned in the above statement?", "options": [{"label": "A", "text": "Algor mortis", "correct": false}, {"label": "B", "text": "Putrefaction", "correct": false}, {"label": "C", "text": "Cadaveric spasm", "correct": false}, {"label": "D", "text": "Livor mortis", "correct": true}], "correct_answer": "D. Livor mortis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Livor mortis Postmortem lividity begins shortly after death. However, it may not be visible for about half to one hour after death in normal individuals and from about one to four hours in anaemic persons. Dull-red patches of 1 to 2 cm. diameter appears in 20 to 30 minutes to two hours. These patches then deepen, increase in intensity and become confluent in one to 4 hours. In the early stage, these patches can be mistaken for bruises. The areas then enlarge and combine to produce extensive discolouration. In some bodies, isolated patches of lividity remain separate from the large areas of lividity resembling contusions.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Algor mortis- It’s the process of cooling down a dead Option B.- Putrefaction is the last stage of decomposition, the destruction of tissues/body. 'The disintegration of body tissues after death is known as decomposition. The terms decomposition and putrefaction are used as synonyms. Putrefaction usually follows the disappearance of rigor mortis. During the hot season, it may commence before rigor mortis has wholly disappeared from the lower extremities. Organisms/bacteria gain entry into tissues mainly from the alimentary tract and also through the respiratory tract, and they multiply in tissues. As they multiply, the bacteria spread via vessels using proteins and carbohydrates of blood as culture media. They release bacterial enzymes. Option C. Cadaveric spasm- Cadaveric spasm (cataleptic rigidity) is a rare condition. In this, the muscles contracted during life become stiff and rigid immediately after death without passing into the stage of primary relaxation. As such, the change preserves the exact attitude of the person at the time of death for several hours afterwards. The spasm is primarily a vital phenomenon that originates from regular nervous stimulation of the muscles. This is usually limited to a single group of voluntary muscles and frequently involves the hands.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Non-displacement and non-shifting of lividity are due to?", "options": [{"label": "A", "text": "Haemoconcentration", "correct": true}, {"label": "B", "text": "Secondary lividity", "correct": false}, {"label": "C", "text": "Incomplete shifting", "correct": false}, {"label": "D", "text": "Complete shifting", "correct": false}], "correct_answer": "A. Haemoconcentration", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Haemoconcentration Non-displacement and non-shifting of lividity is due to haemoconcentration by loss of fluid which penetrates the wall of those vessels related to the hydrostatic pressure. Blood leaks out into the surrounding tissues due to hemolysis and the breakdown of blood vessels.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B . secondary lividity If the body is moved within a few hours after death, patches of lividity will disappear, and new ones will form on dependent parts (secondary lividity). Option: C. In incomplete shifting, lividity appears slightly in the downward-facing parts after turning the body over. Non-displacement and non-shifting of lividity are due to haemoconcentration by loss of fluid which penetrates the wall of those vessels related to the hydrostatic pressure. Option: D. Complete shifting- In complete shifting, if the body is moved within a few hours after death, patches of lividity will disappear, and new ones will form on dependent parts. The new lividity formation is secondary lividity.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "What type of lividity is usually well developed within four hours and reaches a maximum between 6 to 12 hours, and persists until putrefaction sets in", "options": [{"label": "A", "text": "Primary lividity", "correct": true}, {"label": "B", "text": "Secondary lividity", "correct": false}, {"label": "C", "text": "Incomplete shifting", "correct": false}, {"label": "D", "text": "complete shifting", "correct": false}], "correct_answer": "A. Primary lividity", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Primary lividity Primary lividityusually is usually well developed within four hours and reaches a maximum of 6 to 12 hours (primary lividity) and persists until putrefaction sets in. It is present in all bodies but is more clearly seen in the bodies of fair people than in those of the dark. It may not be appreciated in old and anaemic persons.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Secondary lividity -If the body is moved within a few hours after death, patches of lividity will disappear, and new ones will form on dependent parts (secondary lividity). Option: C. In incomplete shifting, after turning the body over, lividity appears slightly in the downward-facing parts. Non-displacement and non-shifting of lividity is due to haemoconcentration by loss of fluid which penetrates the wall of those vessels related to the hydrostatic pressure. Option: D. Complete shifting- In complete shifting, if the body is moved within a few hours after death, patches of lividity will disappear, and new ones will form on dependent parts. The new lividity formation is secondary lividity.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The bluish-purple or purplish-red (due to deoxyhaemoglobin) discolouration, which appears under the skin in the most superficial layers of the dermis (rete mucosum) of the dependent parts of the body after death, due to capillo-venous distention It is also called postmortem staining, subcutaneous hypostasis, livor mortis, cadaveric lividity, suggilations, vibices and darkening of death The extent and the time of appearance of lividity mainly depends upon which of the following factors?", "options": [{"label": "A", "text": "The volume of blood in circulation at the time of death", "correct": false}, {"label": "B", "text": "The length of time that the blood remains fluid after death", "correct": false}, {"label": "C", "text": "Both are wrong", "correct": false}, {"label": "D", "text": "Both are right", "correct": true}], "correct_answer": "D. Both are right", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both are right It mainly depends upon the following:- Option: A. The volume of blood in circulation at the time of death, and Option: B. The length of time that the blood remains fluid after death. Hypostatic congestion resembling postmortem hypostasis may be seen a few hours before death in case of a person dying slowly with circulatory failure, e.g. cholera, typhus, tuberculosis, uraemia, morphine and barbiturate poisoning, congestive cardiac failure, deep coma, and asphyxia. In such cases, hypostasis will be marked shortly after death. If a death has been taking place slowly over a period, early hypostasis may be present before death has occurred, especially when the affected part is already engorged.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A person died on the operation table. His relatives filed a criminal complaint against the doctor. A medical practitioner can be charged with criminal negligence if he:", "options": [{"label": "A", "text": "Exhibits gross lack of competency", "correct": true}, {"label": "B", "text": "Treats a criminal who has committed a murder", "correct": false}, {"label": "C", "text": "Is guilty of contributory negligence", "correct": false}, {"label": "D", "text": "Violates Code of Medical Ethics", "correct": false}], "correct_answer": "A. Exhibits gross lack of competency", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Exhibits gross lack of competency The question of criminal negligence may arise:- When a doctor shows the gross absence of skill or care during treatment resulting in serious injury to or death of the patient, by acts of omission or commission. When a doctor performs an illegal act. When an assaulted person dies, the defense may attribute. The death to the negligence or undue interference in the treatment of the deceased by the doctor.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C, & D. Treating a criminal is not a punishable offense while contributory negligence and violating the code of medical ethics do not come under criminal negligence. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Under which section of IPC a doctor is punishable if convicted of criminal negligence?", "options": [{"label": "A", "text": "304", "correct": false}, {"label": "B", "text": "304 A", "correct": true}, {"label": "C", "text": "304 B", "correct": false}, {"label": "D", "text": "306", "correct": false}], "correct_answer": "B. 304 A", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>304 A 304, A., I.P.C. deals with criminal negligence. \"Whoever causes the death of any person by doing any rash or negligent act not amounting to culpable homicide shall be punished with imprisonment up to 2 years, or with fine, or with both\". According to S.375, Cr.P.C., in addition to imprisonment or other penalty prescribed by the I.P.C., compensation may also have to be paid to the victim of criminal negligence</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: 304, I.P.C.:Punishment for culpable homicide not amounting to murder: Imprisonment for life, or up to 10 years and also fine. Option C: 304-B., I.P.C. (Dowry Death): where the death of a woman is caused by any burn or bodily injury or occurs otherwise than under normal circumstances within seven years of her marriage and it is shown that soon before her death she was subjected to cruelty or harassment by her husband or any relative of her husband for, or in connection with, any demand for dowry, such death shall be called \"dowry death\", and such husband or relative shall be deemed to have caused her death. Option D: 306, I.P.C.: Abetment of suicide: Suicide is the act of taking one's own life voluntarily. If any person commits suicide, whoever abets the commission of such suicide, shall be punished.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In case of medical malpractice, a suit of damages against a doctor can be filed up to:", "options": [{"label": "A", "text": "6 months.", "correct": false}, {"label": "B", "text": "1 year.", "correct": false}, {"label": "C", "text": "2 years", "correct": true}, {"label": "D", "text": "6 years", "correct": false}], "correct_answer": "C. 2 years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>2 years According to the law of limitation, a suit for damages for negligence against the doctor should be filed within two years from the date of alleged negligence. A suit filed after two years will be dismissed as being beyond the period of limitation.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, B, & D: Since the suit should be filed within 2 years, the other Options are not correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient was discharged from outpatient without dressing the wound. Later that day, the patient applied some paste from a local medical man leading to infection of the wound. Contributory negligence may be used as a defense in cases of:", "options": [{"label": "A", "text": "Criminal negligence.", "correct": false}, {"label": "B", "text": "Civil negligence suit", "correct": true}, {"label": "C", "text": "Both civil & criminal negligence cases.", "correct": false}, {"label": "D", "text": "Not useful in both civil & criminal cases.", "correct": false}], "correct_answer": "B. Civil negligence suit", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Civil negligence suit Contributory negligence can be cited as a defense only in civil cases. Contributory negligence is any unreasonable conduct, or absence of ordinary care on the part, of the patient, or his personal attendant, which combined with the doctor's negligence, contributed to the injury complained of, as a direct, proximate cause and without which the injury would not have occurred.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C, & D. Contributory Negligence cannot be used as a defense in criminal cases. Hence Options A and C are not the correct answers. But as mentioned above it can be used in civil negligence cases. Hence Option D is also the wrong answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the following is an example of “Res Ipsa Loquitor”:", "options": [{"label": "A", "text": "Pulmonary embolism after an operation", "correct": false}, {"label": "B", "text": "Infection after an operation", "correct": false}, {"label": "C", "text": "Operation on a wrong organ", "correct": true}, {"label": "D", "text": "Failure to cure", "correct": false}], "correct_answer": "C. Operation on a wrong organ", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Operation on a wrong organ Other examples of Res Ipsa Loquitor Prescribing an overdose of the medicine produces ill effects. Giving poisonous medicine carelessly. Failure to give anti-tetanic serum in cases of injury causing tetanus. Bums from the application of hot water bottles or from X-ray therapy. Breaking of needles. Failure to remove the swabs during the operation may lead to complications or cause death. Operation on the wrong organ Blood transfusion misadventure. Loss of use of hand due to prolonged splinting.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B, & D. Pulmonary Embolism or Infection after an operation are rare effects that cannot be always controlled. Failure to cure is also not an evident mistake from a doctor's Hence these three options do not come under Res Ipsa Loquitor.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient died on the operating table during the induction of anesthesia. During the investigation, the anesthetist was held guilty of negligence. The punishment awarded to a doctor is:", "options": [{"label": "A", "text": "Imprisonment for 2 years", "correct": false}, {"label": "B", "text": "Fine", "correct": false}, {"label": "C", "text": "Imprisonment for 7 years", "correct": false}, {"label": "D", "text": "2 years imprisonment and fine", "correct": true}], "correct_answer": "D. 2 years imprisonment and fine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>2 years imprisonment and fine 304, A., I.P.C. deals with criminal negligence. \"Whoever causes the death of any person by doing any rash or negligent act not amounting to culpable homicide shall be punished with imprisonment up to 2 years, or with fine, or with both\". According to S.375, Cr.P.C., in addition to imprisonment or other penalty prescribed by the I.P.C., compensation may also have to be paid to the victim of criminal negligence.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A : It suggests only imprisonment for 2 years and not about the fine. Hence it is the wrong answer. Option B : It suggests only a fine and not imprisonment. Hence it is also not the correct option. Option C : It suggests an imprisonment of 7 years while the actual punishment is of 2 years with a fine. Hence it is also not the correct answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During an operation, if a pair of scissors is left in the abdomen which was recovered in a subsequent surgery. The doctrine applicable is:", "options": [{"label": "A", "text": "Res Integra", "correct": false}, {"label": "B", "text": "Res Ipsa Loquitor", "correct": true}, {"label": "C", "text": "Res Judicata", "correct": false}, {"label": "D", "text": "Vicarious Liability", "correct": false}], "correct_answer": "B. Res Ipsa Loquitor", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Res Ipsa Loquitor But appeal to a higher court is allowed. Ordinarily, the professional negligence of a physician must be proved in Court by the expert evidence of another physician. The patient need not prove negligence in a case where the rule of res ipsa loquitur applies, which means \"the thing or fact speaks for itself\". The patient has to merely state what according to him the act of negligence was. Conditions to be satisfied: That in the absence of negligence the injury would not have occurred ordinarily; That the doctor had exclusive control over the injury-producing instrument or treatment; That the patient was not guilty of contributory negligence. This enables the patient's lawyer to prove his case without medical evidence. Examples: Prescribing an overdose of the medicine produces ill effects. Giving poisonous medicine carelessly. Failure to give anti-tetanic serum in cases of injury causing tetanus. Bums from the application of hot water bottles or from X-ray therapy. Breaking of needles. Failure to remove the swabs during the operation may lead to complications or cause death. Blood transfusion misadventure. Loss of use of hand due to prolonged splinting.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Res Integra: An entirely new matter. Those points of law have not yet been decided. Option C: Res Judicata (the thing has already been decided)- If a case of negligence against a doctor has already been decided in one court, the patient cannot start fresh proceedings in another court. Option D: VICARIOUS LIABILITY (liability for the actions of another): An employer is. responsible not only for his own negligence but also for the negligence of his employees, if such acts occur in the course of the employment and within its scope, by the principle of respondeat superior</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Sometimes, the doctors and their teams work hard to save a patient. However, the facility provided by the hospital is below standard. The court can hold the hospital responsible for corporate negligence. Corporate negligence means, when the hospital:", "options": [{"label": "A", "text": "Provides defective instruments", "correct": false}, {"label": "B", "text": "Retains incompetent employees", "correct": false}, {"label": "C", "text": "Fails to provide the accepted standard of care", "correct": false}, {"label": "D", "text": "All the above", "correct": true}], "correct_answer": "D. All the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All the above CORPORATE NEGLIGENCE: The theory of corporate liability is typically applied in cases involving hospitals and their staff physicians. Hospitals have an independent duty to their patients to investigate the adequacy and review the competence of staff physicians, This theory is based on the principle that hospitals are in a far better position than their patients to supervise a physician's performance and provide quality control. This legal theory has been used to attack the allegedly negligent selection, retention, or supervision of its participating physicians, which is negligent credentialing. It is the failure of those persons who are responsible for providing the accommodation, facilities, and treatment to follow the established standard of conduct.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B, & C. It occurs when the hospital provides defective equipment or drugs, selects or retains incompetent employees, or fails in some other manner to meet the accepted standard of care, and such failure results in injury to a patient to whom the hospital owes a duty. In the corporate sector (hospital, nursing home, etc.)., where more than one person at more than one level fails to render appropriate service to the patient, may result in some damage to the patient. Here the treating doctor and also other categories of persons who were negligent will be held responsible.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A mentally ill person was brought to court. Durham’s and Curren’s rule deals with:", "options": [{"label": "A", "text": "Criminal responsibilities of an insane person", "correct": true}, {"label": "B", "text": "Civil responsibilities of an insane person", "correct": false}, {"label": "C", "text": "Consent of girl for sexual intercourse", "correct": false}, {"label": "D", "text": "Consent of a patient for a dangerous operation", "correct": false}], "correct_answer": "A. Criminal responsibilities of an insane person", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Criminal responsibilities of an insane person TESTS TO DETERMINE CRIMINAL RESPONSIBILITY ARE Naughten’s rule Durham rule Curren’s rule The Irresistible Impulse test (New Hampshire Doctrine) The American Law Institute Test The Federal Rule</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C, & D: Durhams and Currens Rule are not related to civil responsibilities, consent for sexual intercourse, or consent from a patient. Hence these options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A doctor has been brought to the court on account of civil negligence and demand for compensation. In the trial, the doctor pointed out that the case had already been decided by another court and he was cleared of the case. Which of the defenses has the doctor effectively taken?", "options": [{"label": "A", "text": "Res ipsa loquitur", "correct": false}, {"label": "B", "text": "Res judicata", "correct": true}, {"label": "C", "text": "Respondent superior", "correct": false}, {"label": "D", "text": "Novus actus interveniens", "correct": false}], "correct_answer": "B. Res judicata", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Res judicata Res judicata (S. 300, Cr.P.C.). If a question of negligence against a doctor has already been decided by a Court in a dispute between the doctor and his patient. The patient will not be allowed to contest the same question in another proceeding between himself and the doctor on the same set of facts. Only appeals can be made.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Res Ipsa Loquitur - The patient need not prove negligence in a case where the rule of res ipsa loquitur applies, which means \"the thing or fact speaks for itself\". Option C: VICARIOUS LIABILITY (liability for the actions of another): An employer is. responsible not only for his own negligence but also for the negligence of his employees, if such acts occur in the course of the employment and within its scope, by the principle of respondeat Option D: NOVUS ACTUS INTERVENIENS: A person is responsible not only for his actions but also for the logical consequences of those actions.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The term ‘commorientes’ refers to:", "options": [{"label": "A", "text": "Simultaneous death of more than 100 persons in a mass disaster", "correct": false}, {"label": "B", "text": "Mass disaster due to a human mistake, such as a fire in a building due to short-circuiting", "correct": false}, {"label": "C", "text": "A special form of mass disaster when planes are crashed into buildings", "correct": false}, {"label": "D", "text": "Two or more people dying simultaneously or in circumstances rendering it uncertain which one of them survived the other", "correct": true}], "correct_answer": "D. Two or more people dying simultaneously or in circumstances rendering it uncertain which one of them survived the other", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Two or more people dying simultaneously or in circumstances rendering it uncertain which one of them survived the other which one of them survived the other Commorientes: Persons who die together on the same occasion, where it cannot be ascertained who died first. In these scenarios, the court applies the doctrine of survivorship.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, B, & D: Simultaneous death of more than 100 people, or a mass disaster even if the human origin is not related to commorientes. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In Negligence suits, the defense of Contributory Negligence by a doctor is limited by", "options": [{"label": "A", "text": "Res judicata", "correct": false}, {"label": "B", "text": "Last clear chance doctrine", "correct": true}, {"label": "C", "text": "Res ipsa loquitor", "correct": false}, {"label": "D", "text": "Doctrine of Novus Actus Interveniens", "correct": false}], "correct_answer": "B. Last clear chance doctrine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Last clear chance doctrine LAST CLEAR CHANCE DOCTRINE : If the doctor fails to prevent damage resulting from the negligent act of the patient, even after getting clear time, he cannot plead contributory negligence in civil cases.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options :- Option: A. Res judicata (S. 300, Cr.P.C.). If a question of negligence against a doctor has already been decided by a Court in a dispute between the doctor and his patient. The patient will not be allowed to contest the same question in another proceeding between himself and the doctor on the same set of facts. Only appeals can be made. Option: C. Res ipsa Loquitur : A doctrine or rule of evidence in a civil negligence case that permits an inference or presumption that the doctor was negligent in an accident injuring the patient on the basis of circumstantial evidence if the accident was of a kind that does not ordinarily occur in the absence of negligence. Option: D. 'NOVUS ACTUS INTERVENIENS: (Breaking the chain): It refers to the idea that causal connections are deemed to finish. Even if the doctor can be shown to have acted negligently, there will be no liability if some new intervening act breaks the chain of causation between that negligence and the loss or damage sustained by the patient.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 22 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A doctor was giving evidence in a court. He decided to divulge the details of a patient. Professional secrecy can be divulged:", "options": [{"label": "A", "text": "If the doctor feels so.", "correct": false}, {"label": "B", "text": "On demand by the court.", "correct": false}, {"label": "C", "text": "Both.", "correct": true}, {"label": "D", "text": "None of the above.", "correct": false}], "correct_answer": "C. Both.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both. The doctor can divulge professional secrecy if he feels so or on demand by the court in criminal cases. (Option A, B and C) Any divulgence, therefore, will amount to a breach of contract, trust and confidence, and will render the doctor liable for damages. T The secrets may be learnt from the patient or found on examination or noticed in the usual privacies of domestic life. Consequently, most commentators include privacy and confidentiality in this context.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A doctor is justified in divulging professional secrets in the:", "options": [{"label": "A", "text": "Infectious diseases", "correct": true}, {"label": "B", "text": "Malignant diseases", "correct": false}, {"label": "C", "text": "Occupational diseases", "correct": false}, {"label": "D", "text": "In reporting a case in any medical Journal", "correct": false}], "correct_answer": "A. Infectious diseases", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Infectious diseases If a patient suffering from an infectious disease is employed as a cook or waiter in a hotel, or a food handler with an enteric infection, or a teacher with tuberculosis or other infective diseases, or as a children's nurse, etc., he should be persuaded to leave the job until he becomes non-infectious. If the patient refuses to accept this advice, the doctor can inform the employer about the illness of his patient. Maintaining confidentiality about such things might put other’s life at risk.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C, & D: A patient suffering from a Malignant disease or an occupational disorder is no harm to other people knowingly or unknowingly. Hence a doctor does not have to divulge professional secrets.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Privileged communication is needed to communicate details of the patient to various authorities and other persons. The patient can sue the doctor for damage for revealing:", "options": [{"label": "A", "text": "Professional secrets if the disclosure voluntarily", "correct": false}, {"label": "B", "text": "Has resulted in harm to the patient", "correct": false}, {"label": "C", "text": "Is not in the interest of the patient", "correct": false}, {"label": "D", "text": "All of above", "correct": true}], "correct_answer": "D. All of above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of above A doctor should not discuss the illness of his patient with others without the consent of the patient. If the patient is major, the doctor should not disclose any facts about the illness without his consent to parents or relatives even though they may be paying the doctor's fees. In the case of a minor or an insane person, guardians or parents should be informed of the nature of the illness. A doctor should not answer any enquiry by third parties even when enquired by near relatives of the patient, either with regard to the nature of the illness or with regard to any subsequent effect of such illness on the patient without the consent of the patient. A doctor should not disclose any information about the illness of his patient without the consent of the patient even when requested by a public or statutory body, except in case of notifiable diseases. If the patient is a minor or insane, consent of the guardian should be taken. Even in the case of husband and wife, the facts relating to the nature of illness of the one, must not be disclosed to the other, without the consent of the concerned person. In divorce and nullity cases, no information should be given without getting the consent of the person concerned. Medical officers in Government service are also bound by the code of professional secrecy, even when the patient is treated for When a doctor examines a Government servant on behalf of the Government, he cannot disclose the nature of the illness to the Government without the patient's consent. When a domestic servant is examined at the request of the master, the doctor should not disclose any facts about the illness to the master without the consent of the servant, even though the master is paying the fees. The medical officer of a firm or factory should not disclose the result of his examination of an employee to the employers without the consent of the employee. (11) A person in police custody as an under-trial prisoner has the right not to permit the doctor who has examined him, to disclose the nature of his illness to any person. If a person is convicted, he has no such right and the doctor can disclose the result to the authorities. In reporting a case in any medical journal, care should be taken that patient's identity is not revealed from the case notes or photographs. In the examination of a dead body, certain facts may be found, the disclosure of which may affect the reputation of the deceased or cause mental suffering to his relatives, and as such, the doctor should maintain secrecy. The medical examination for taking out a life insurance policy is a voluntary act by the examinee, and therefore consent to the disclosure of the finding may be taken as implied. A doctor should not give any information to an insurance company about a person who has consulted him before, without the patient's consent. Any information regarding a dead person may be given only after obtaining consent from the nearest relative. The sex of the unborn detected during ultrasonography should not be disclosed.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person attended the outpatient with a thrush in his mouth. He was diagnosed with HIV infection. The person requested the physician not to divulge the information to his parents. The physician assures the patient about professional secrecy. Professional secrecy is a:", "options": [{"label": "A", "text": "Legal responsibility", "correct": false}, {"label": "B", "text": "Ethical responsibility", "correct": false}, {"label": "C", "text": "Social responsibility", "correct": false}, {"label": "D", "text": "Implied term of the contract between doctor and patient", "correct": true}], "correct_answer": "D. Implied term of the contract between doctor and patient", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Implied term of the contract between doctor and patient As per definition, Professional secrecy is an implied term of the contract between a doctor and his patient. It is a DUTY of the doctor i.e. the doctor should keep secret whatever he has acquired as part of his professional work from the patient. If the doctor discloses anything then the patient can sue him for damages/fine in a court of law. The doctor should not disclose anything about the patient without the written consent of the patient; if he is a minor or insane the parents/guardians should be informed of the patient’s illness. However, in the case of Notifiable diseases, the public health authorities should be informed about the patient’s illness. Doctors can be charged with Defamation for disclosing the secrets of their</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, B, & C: It doesn't come under any responsibilities of the doctor rather is an implied term of the Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted with STD. The person was apprehended that his STD information will be communicated to his wife. The doctor assured him that barring some situations, the hospital does not communicate such things. Privileged communication is given for all of the following EXCEPT:", "options": [{"label": "A", "text": "Negligence suite", "correct": false}, {"label": "B", "text": "Preventing a person suffering from STD from taking a job as a car driver", "correct": true}, {"label": "C", "text": "Benefit of society", "correct": false}, {"label": "D", "text": "A doctor for saving himself in the court of law", "correct": false}], "correct_answer": "B. Preventing a person suffering from STD from taking a job as a car driver", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Preventing a person suffering from STD from taking a job as a car driver Privileged communications: a statement made bonafide upon any subject matter by a doctor to the concerned authority due to his duty to protect the interest of the community or of the State (the exception to the general rule of professional secrecy).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, C & D Examples of Privileged Communications Infectious diseases: e.g. If a patient suffering from cholera, typhoid, etc is employed as a cook in a hotel, he should not be allowed to work until becomes non-infectious; if the patient refuses → the doctor can inform the employer. Servants & employers: e.g. The engine driver suffering from epilepsy, color blindness, etc should get it treated before being allowed to work. Otherwise, Doctor can inform the employer Venereal disease: e.g. A person suffering from Syphilis is about to marry– first advise not to marry till he cures, otherwise, the doctor can inform the spouse concerned Option: A. Negligence suits against the doctor. Option: C. Notifiable diseases: Doctor has the duty to notify birth, death, and infectious diseases to the public health authorities. Suspected crime. Patient’s own interest- e.g. doctor may inform the guardian of the patient about the suicidal tendency of the patient Option: D. Courts of law.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "One of the functions of NMC is to issue a list of infamous conducts. All of the following are Infamous Conduct except:", "options": [{"label": "A", "text": "Dichotomy", "correct": false}, {"label": "B", "text": "Adultery", "correct": false}, {"label": "C", "text": "Criminal abortion", "correct": false}, {"label": "D", "text": "Dispensing Medicine", "correct": true}], "correct_answer": "D. Dispensing Medicine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Dispensing Medicine Infamous conduct includes malfeasance, misdemeanour, delinquency and offence. It is something more than accident or negligence/carelessness and is the culpable neglect of an official/professional in regard to the office/profession. It implies some degree of men’s rea on the part of the person concerned or, at any rate, a very grave degree of negligence, or serious failure to carry out the instruction.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Various indices have been developed for identification to avoid subjective errors during the examination of the skeleton. The cephalic index is related to the determination of:", "options": [{"label": "A", "text": "Age", "correct": false}, {"label": "B", "text": "Sex", "correct": false}, {"label": "C", "text": "Religion", "correct": false}, {"label": "D", "text": "Race", "correct": true}], "correct_answer": "D. Race", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Race Race can be determined by Cephalic index Complexion Eyes Hair Clothes Racial difference in the skull Type of Skull Cephalic Index Race (1) Dolico-cephalic (long-headed) 70 to 75 Pure Aryans, Aborigines, and Negroes. (2) Mesati-cephalic(medium-headed) 75 to 80 Europeans Chinese and Indians. (3) Brachy-cephalic (short-headed) 80 to 85 Mongolian.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Various indices are nowadays used to determine the sex of skeletal remains, especially, the sternum, pelvis and sacrum. Which of the following index is more in males compared to females?", "options": [{"label": "A", "text": "Sternal index", "correct": false}, {"label": "B", "text": "Ischiopubic index", "correct": false}, {"label": "C", "text": "Sciatic index", "correct": false}, {"label": "D", "text": "Corporobasal index", "correct": true}], "correct_answer": "D. Corporobasal index", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Corporobasal index Corporobasal index of sacrum: - The breadth of the first sacral vertebra x 100 is divided by the Breadth of the base of the sacrum. Its value is 45 in males and 40.5 in females.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Sternal index:-its 46.2 in males and 54.3 in females Option: B. Ischiopubic index:- its 73 to 94 in males and 91 to 115 in females Option: C. Sciatic index:-its 4 to 5 in males and 5 to 6 in females</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "After the age of 25 years when all the long bone epiphyses are fused, skull suture and symphysis changes are used for age estimation. Which of the skull sutures fuses the earliest?", "options": [{"label": "A", "text": "Coronal", "correct": false}, {"label": "B", "text": "Sagittal", "correct": false}, {"label": "C", "text": "Lambdoid", "correct": false}, {"label": "D", "text": "Metopic", "correct": true}], "correct_answer": "D. Metopic", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Metopic The metopic suture closes about the third year, but in 5 to I0% of cases, it persists. The basioccipital fuses with the basisphenoid at about 18 to 21 years.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B, & C The coronal, sagittal, and lambdoid sutures start to close on their inner side at about the age of 25 years. On the outer side, fusion occurs in the following order: posterior one-third of the sagittal suture at about 30 to 40 years: anterior one-third of the sagittal and lower half of the coronal at about 40 to 50 years: and middle sagittal and upper half of the coronal at about 50 to 60 years. The lambdoid suture starts closing near the lambda and the union is often completed at about 45 years. The squamous part of the temporal bone usually fuses with its neighbour by age of 60 years</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A humerus is brought for examination by a police officer which has a length of 30 cm. What would have been the estimated height of the individual?", "options": [{"label": "A", "text": "120 cm", "correct": false}, {"label": "B", "text": "180 cm", "correct": false}, {"label": "C", "text": "150 cm", "correct": true}, {"label": "D", "text": "100 cm", "correct": false}], "correct_answer": "C. 150 cm", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>150 cm Height of humerus= length of long bone* multiplication factor of humerus; 30*5.3= 159</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The following skull is seen in:", "options": [{"label": "A", "text": "West Asians", "correct": false}, {"label": "B", "text": "Indian", "correct": false}, {"label": "C", "text": "European", "correct": false}, {"label": "D", "text": "Negros", "correct": true}], "correct_answer": "D. Negros", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/questionImage-1687169566270-QTDF014007IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Negros NEGRO (BLACK): The lower face projects forward (facial Prognathism), the skull narrow and elongated, the orbits square, the nasal aperture broad, and nasal sill guttered, the palate rectangular, and upper and lower limbs longer. Brachycephaly is due to the fusion of coronal sutures. Dolichocephaly is due to the fusion of the sagittal sutures.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B, & C. CAUCASIAN (WHITE): (Europeans, West Asians, Asian Indians, and some Americans). Skull tends to be high with an almost completely straight lower face (orthognathism). Skull rounded, orbits triangular, nasal aperture elongated, and nasal sill very sharp-edged, palate triangular, upper and lower limbs normal in proportion to the body.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "You are attending your final professional FMT practical. During your final viva, the external examiner shows you the following image (no image is provided/required for this question)of the firearm and asks about the calibre of the following gun. Which of the following describes the calibre of the gun?", "options": [{"label": "A", "text": "It is measured as the distance between two grooves.", "correct": false}, {"label": "B", "text": "It is measured as the distance between two opposite lands.", "correct": true}, {"label": "C", "text": "It is measured as the distance between two opposite land and groove.", "correct": false}, {"label": "D", "text": "None of the above.", "correct": false}], "correct_answer": "B. It is measured as the distance between two opposite lands.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>It is measured as the distance between two opposite lands. The calibre of the rifle is measured as the distance between opposite lands. hence it is a correct statement. Given below image depicts the calibre of the rifled forearm</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You are evaluating a gunshot wound, as shown in the image below. Mark the statement which holds for the following image-", "options": [{"label": "A", "text": "In the given image, tattooing is not seen.", "correct": false}, {"label": "B", "text": "It is a contact shot wound", "correct": false}, {"label": "C", "text": "Blackening and burning are seen.", "correct": true}, {"label": "D", "text": "It is a shotgun wound.", "correct": false}], "correct_answer": "C. Blackening and burning are seen.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891703963-QTDF007002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Blackening and burning are seen. From the given image, we can conclude that it is a rifled firearm wound with a bullet used. In the given image, blackening and burning are seen, but tattooing is not visible. But when blackening and burning are present, then tattooing is also current. Hence option A is a wrong statement. These are the features of the close-range wound. The centre hole is of the bullet, surrounding which bullet wipe, grease and abrasion collar are present.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. It is not a contact shotgun wound as there is no muzzle impression, and blackening, burning, and tattooing are present along the entry tract. Option: D. It is not a shotgun wound, as we can see a large central hole representing a bullet's entry. Shotgun contains small pellets.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You are provided with three sets of images to interpret range in case of a firearm wound during your post-graduation in fmt. Which of the following images depicts a contact wound from a rifled forearm?", "options": [{"label": "A", "text": "A, c", "correct": false}, {"label": "B", "text": "B, c", "correct": true}, {"label": "C", "text": "A, d", "correct": false}, {"label": "D", "text": "C only", "correct": false}], "correct_answer": "B. B, c", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891706248-QTDF007004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>B, c Both of them depict the contact range shot of the rifled firearm. In image b, we can see the muzzle impression; no blackening, burning, or tattooing is seen on the skin surface. Image: A. shows a close-range shot as there is burning, blackening and tattooing along with a bullet hole. Image: C . Depicts a cruciate wound on the skin surface due to a contact wound on a bony shell. Image: D. also depicts a close-range wound.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 25-year-old male was shot dead while coming home from college. Police were informed, and they reached the crime scene along with the forensic Team. The image of the wound is given below. Which of the following statement is correct wrt the following image?", "options": [{"label": "A", "text": "A distant-range shot caused the wound.", "correct": false}, {"label": "B", "text": "The bullet has entered the skin at an angle of 30 degrees.", "correct": false}, {"label": "C", "text": "The wound has blackening and tattooing.", "correct": true}, {"label": "D", "text": "It is an exit wound.", "correct": false}], "correct_answer": "C. The wound has blackening and tattooing.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891707788-QTDF007005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The wound has blackening and tattooing. The given image depicts a close-range shot by a rifled firearm, as we can see a bullet hole in the centre. Close range shot is characterised by blackening, burning and tattooing. It can also cause hair singeing due to the burning effect of flame. It does not contain a muzzle impression.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. The wound was caused by a distant range shot is a wrong statement as it would not have the presence of tattooing, blackening, or burning around the wound. Option: B. The bullet has entered the skin at an angle of 30 degrees is a wrong statement as in that the abrasion collar would have been asymmetrical around the wound. Option: D. It is not an exit wound as it contains signs like blackening, burning, and tattooing, and the size of the wound is also tiny. Hence all other statements are incorrect except option c.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You are one of the forensic expert Team members investigating the case of a 34-year-old woman shot dead by her husband with a pistol over an argument regarding the husband's affair with her secretary. After the crime scene investigation, the dead body was sent for further investigation. The image of the wound is given below. At what distance was the firearm fired?", "options": [{"label": "A", "text": "Contact shot", "correct": false}, {"label": "B", "text": "5-10 cm", "correct": false}, {"label": "C", "text": "30-45 cm", "correct": true}, {"label": "D", "text": "60-70 cm", "correct": false}], "correct_answer": "C. 30-45 cm", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891709848-QTDF007006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>30-45 cm 30-45 cm. Only tattooing is visible in the given image, along with a slight bullet entry hole characteristic of near-range shots. The skin is out of reach of flame and smoke deposition at this range. Hence blackening and burning are not seen.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Contact shot will not lead to tattooing. Option: B. 5-10 cm range will produce a wound of the close range, which will have to blacken and burn. Option: D. 60-70 cm(>50 cm) at long range, there are no signs except for the bullet hole, which will even be smaller than this.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You were reading a forensic report mentioning the range of the gunshot wound. It describes the wound as ‘ a central bullet entry wound surrounded by grease collar and abrasion collar along with blackening, burning and tattooing around the wound present. There was also the presence of singeing of the hair. Which of the following statements correctly describes the various terminology in the above statement?", "options": [{"label": "A", "text": "Abrasion collar- it is caused by the removal of bullet lubrication and deposition as it passes through the skin.", "correct": false}, {"label": "B", "text": "Burning and singeing of the skin is caused by the deposition of the smoke particles.", "correct": false}, {"label": "C", "text": "Tattooing occurs as a result of deposition of unburnt smoke particle around the entry wound", "correct": true}, {"label": "D", "text": "Tattooing can be wiped off with the help of a wet cloth.", "correct": false}], "correct_answer": "C. Tattooing occurs as a result of deposition of unburnt smoke particle around the entry wound", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Tattooing occurs as a result of deposition of unburnt smoke particle around the entry wound In the given description, one can easily corroborate that the wound is an entry wound with range to be a close range gunshot wound. Only statement c is correct.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Abrasion collar is caused by striking of the bullet to the skin which results in indentation and stretching of the skin. Bullet lubrication results in bullet wipe/ grease collar. Option: B. Burning and singeing of the skin is caused by flame effect of the gunshot and not by deposition of the smoke particles which results in blackening. Option: D. Tattooing is deposition of an unburnt smoke particle on the skin surface which cannot be wiped off. Hence it is a wrong statement.D . Tattooing is deposition of an unburnt smoke particle on the skin surface which cannot be wiped off. Hence it is a wrong statement.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A woman was found dead in her farm house after a quarrel with her boyfriend. At the crime scene, she was found lying on the floor, with a gun in her hand. The entry wound was present on the right side of the forehead just above the ear. Interestingly, no exit wound was found on the other side. After the autopsy examination, the bullet was found inside the body in a different track compared to the firing direction. Which of the following terms best describes the phenomena observed?", "options": [{"label": "A", "text": "Tumbling bullet", "correct": false}, {"label": "B", "text": "Welding of the shots", "correct": false}, {"label": "C", "text": "Richochet effect", "correct": true}, {"label": "D", "text": "Souvenir bullet", "correct": false}], "correct_answer": "C. Richochet effect", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Richochet effect In the given question, it describes the bullet rather than exiting the head, travelling inside the brain in a different track, the most appropriate answer will be option c. Sometimes, after passing through the brain, there is not enough energy left in the bullet to penetrate the skull. It may rebound (ricochet) from the inner table of the skull, producing a second track. If it ricochets for a second time, a third wound track is produced.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect options:- Option: A .Tumbling bullet is a type of bullet that rotate end to end during its motion. Option: B . Balling or welding of the shots- it results in conversion of the shotgun pellets into a compact mass, which can travel for a few metres in this form. In such cases, a circular or oval entrance wound of about 5 to 10 mm is observed. In diameter, and widespread, small, circular punctures are seen, suggesting the use of two different weapons, one a shotgun at distant range and the other a rifle. This can be due to faulty manufacture or old ammunition. Option: D . Souvenir bullet - it is the formation of a fibrotic capsule around the very old retained bullet in the body.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In the given image, there are more than one gunshot wounds. Which of the following is the sequence in which they were shot?", "options": [{"label": "A", "text": "1>2>3", "correct": true}, {"label": "B", "text": "2>1>3", "correct": false}, {"label": "C", "text": "1>3>2", "correct": false}, {"label": "D", "text": "All were shot at the same time.", "correct": false}], "correct_answer": "A. 1>2>3", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891710043-QTDF007011IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1>2>3 The given question is a clinical application of the puppe’s rule. It is used to determine the sequence of the shots, when severe bullets struck the cranium. This rule is applicable to any multiple blunt forces, causing skull fracture. Hence the correct answer is option a.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A girl came to see the gynecologist for primary amenorrhoea The Image below is of:", "options": [{"label": "A", "text": "True hermaphroditism", "correct": false}, {"label": "B", "text": "Pseudo hermaphroditism", "correct": false}, {"label": "C", "text": "Klinefelter’s syndrome", "correct": false}, {"label": "D", "text": "Turners syndrome", "correct": true}], "correct_answer": "D. Turners syndrome", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891917097-QTDF015001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Turners syndrome TURNER'S SYNDROME: It is the most common sex chromosome abnormality of human females. Its incidence in the newborn is about 1 in 2500. In this condition, the anatomical structure is female, but the nuclear sexing is male. It can be recognized at birth by edema of the dorsum of the hands and feet, loose skin folds in the nape of the neck, low birth weight, and short stature. It is characterized by primary amenorrhoea, sterility, lack of development of primary and secondary sexual characteristics, increased urinary gonadotrophin excretion, pigmented naevi, a short fourth metatarsal, webbed-neck, shield chest, wide-set nipples, high-arched palate, low-set ears, slow growth, learning problems, spina bifida, coarctation of the aorta, septal defects, renal defects.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. True Hermaphroditism: This is a very rare condition of bisexuality in which an ovary and a testicle or two ovotestes are present with the external genitalia of both sexes. The gonad may be abdominal, inguinal or labio-scrotal in position. There may be a Phallus may be penile or clitoral; the labia may be bifid as in female or fused resembling the scrotum of the male. Neither gonad is completely functional. The somatic sex chromatin may be male or female Option: B. Pseudohermaphroditism: In this condition, gonadal tissue of only one sex is seen internally, but the external appearance is of the opposite sex. (A)Male pseudohermaphroditism: Nuclear sex is XY, but sex organs and sexual characteristics deviate to the female form, because of testicular feminization. It is characterized by primary amenorrhoea, female external genitalia, normal size breasts, and scanty or absent axillary and pubic hair. Testes are in the abdomen or inguinal canal; 5-a reductase deficiency occurs. (B) Female pseudohermaphroditism: Nuclear sex is XX, but the deviation of sex organs and sexual characters towards males are seen, due to adrenal hyperplasia. 21 hydroxylase deficiency is the most common. Option: C. KLINEFELTER'S SYNDROME:- In this condition, the anatomical structure is male, but the nuclear sexing is female. The sex chromosome pattern is XXY (47 chromosomes). It is usually diagnosed when there is a delay in the onset of puberty, behavioral disorders and mental retardation. Axillary and pubic hair are absent, and hair on the chest and chin are reduced. Gynaecomastia, azoospermia, low levels of testosterone, sterility, increased urinary gonadotrophins, signs of eunuchoidism, and increased height are common. Testicular atrophy with hyalinization of seminiferous tubules is seen histologically. Hypergonadotropic hypogonadism (defective development of testes or ovaries and excess pituitary gonadotropin secretion) is seen.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During the bone examination, only a pelvis was available for identification. True statement about the female pelvis is :", "options": [{"label": "A", "text": "Sub pelvic arch-acute", "correct": false}, {"label": "B", "text": "Obturator foramen-triangular.", "correct": true}, {"label": "C", "text": "Sciatic notch-acute.", "correct": false}, {"label": "D", "text": "Sacrum-long", "correct": false}], "correct_answer": "B. Obturator foramen-triangular.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Obturator foramen-triangular. Female pelvis: General pelvic shape flat bowl. Sub pelvic arch-obtuse. Obturator foramen-triangular. (Option B) Sciatic notch-obtuse. Sacrum-short and flat. Male pelvis: General pelvic shape deep funnel. Sub pelvic arch-acute. (Option A) Obturator foramen-oval Sciatic notch-acute. (Option C) Sacrum-long and curved. (Option D)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Krogman’s formula is an important aspect of identification, especially when using skeletal remains. This formula is related to:", "options": [{"label": "A", "text": "Age", "correct": false}, {"label": "B", "text": "Sex", "correct": true}, {"label": "C", "text": "Religion", "correct": false}, {"label": "D", "text": "Race", "correct": false}], "correct_answer": "B. Sex", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sex Krogman’s formula is related to sex. According to Krogman, the degree of Accuracy in sexing adult skeletal remains is: Entire skeleton:-100 percent Pelvis alone:- 95 percent Skull alone:- 90 percent Pelvis plus skull:-98 percent Long bones alone:- 80 percent</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A bundle of bone, which was recovered from a jungle, is brought by police for post-mortem examination. Examination of which bone will give the maximum idea about the sex of the individual?", "options": [{"label": "A", "text": "Skull", "correct": false}, {"label": "B", "text": "Sternum", "correct": false}, {"label": "C", "text": "Pelvis", "correct": true}, {"label": "D", "text": "Femur", "correct": false}], "correct_answer": "C. Pelvis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Pelvis According to Krogman’s formula, pelvis is the most accurate bone to determine the sex of the individual. According to Krogman, the degree of accuracy in sexing adult skeletal remains is: Entire skeleton:-100 percent Pelvis alone:- 95 percent Skull alone:- 90 percent Pelvis plus skull:- 98 percent Long bones alone:- 80 percent</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A medical student was asked to differentiate the skull of a male from a female. Which of the following statements is not true regarding the skull bone of a male in comparison to that of a female?", "options": [{"label": "A", "text": "Glabella is more prominent", "correct": false}, {"label": "B", "text": "Muscular impressions prominent", "correct": false}, {"label": "C", "text": "Orbits square", "correct": false}, {"label": "D", "text": "Frontal eminence is more prominent", "correct": true}], "correct_answer": "D. Frontal eminence is more prominent", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Frontal eminence is more prominent MALE FEMALE Glabella Rough and more prominent Smooth, small, or absent Muscular impressions Muscle ridges are more prominent Smooth Orbit Square Rounded Frontal eminence Small Large</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A bone can give a lot of information about a person such as height, age, and cause of death. The length of the bone for measuring the stature of an individual is best estimated by:", "options": [{"label": "A", "text": "Measuring tape", "correct": false}, {"label": "B", "text": "Calipers", "correct": false}, {"label": "C", "text": "Osteometric board", "correct": true}, {"label": "D", "text": "Any of the above", "correct": false}], "correct_answer": "C. Osteometric board", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Osteometric board The length of bones to measure the stature is best estimated by the osteometric board; measurement by the use of tapes or calipers are not accurate. (Option A and B). If an osteometric board is not available, the bones should be measured on a flat bench with the maximum lengths taken between two vertical, parallel boards placed in contact with the bone ends. If the bones are covered with articular cartilage, subtract for radius and humerus 3 mm each, the tibia 5 mm. and the femur 7 mm before applying the formulae.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A known gangster was admitted to emergency after a shootout with police personnel. An inquiry was started to investigate police encounters. In gun-shot wound, distance assessment is done from:", "options": [{"label": "A", "text": "Entry wound without singeing and tattooing", "correct": true}, {"label": "B", "text": "Number of pellets", "correct": false}, {"label": "C", "text": "Colour of wound", "correct": false}, {"label": "D", "text": "Size of wound", "correct": false}], "correct_answer": "A. Entry wound without singeing and tattooing", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Entry wound without singeing and tattooing The number of pellets and the Colour of the wound are not related to the distance of the firearm weapon from the victim. The size of the wound has only a limited relationship with the distance of the firearm weapon; in any case not reliable. When we say that the 'Entry wound without singeing and tattooing' means that the distance of the firearm weapon at the time of discharge is more than the range of tattooing,e., more than 60 cm. RANGE INCHES (BARREL TO SKIN) PHYSICAL PROPERTIES Contact 0 Soot, seared skin, triangular tears Close 0-6 Soot, abrasion collar (abrasion collar may be obscured by soot) Intermediate <48 Tattooing, abrasion collar Distant or indeterminate Any distance Abrasion collar (intermediate objects will prevent soot and gunpowder from contacting the skin)</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B, C, & D The number of pellets, color, and size of the wound does not correlate with the distance of the gunshot.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A surgeon was exploring a gunshot wound on the chest. Police personnel informed the surgeon about the faulty gun. In tandem bullets, the number of bullets fired is:", "options": [{"label": "A", "text": "1", "correct": false}, {"label": "B", "text": "2", "correct": true}, {"label": "C", "text": "3", "correct": false}, {"label": "D", "text": "4", "correct": false}], "correct_answer": "B. 2", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>2 In tandem bullets, the number of shots fired is two. Tandem Bullet or piggyback bullet (tandem = one behind the other)- Occasionally, more bullets are found than the number of entrance wounds. This occurs due to defects in the weapon, faulty ammunition, or a loaded firearm that has been unused for several years.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 28-year-old male, while returning home after completing his work, was caught by a few thieves. They were trying to snatch things from him, and during the fight, he was being shot by the thieves. He was dead by the time he was taken to the hospital. During the autopsy examination, the following finding was noted. Which of the following statement about the type of firearm used is correct?", "options": [{"label": "A", "text": "It is a wound which is caused by a shotgun that is rifled", "correct": false}, {"label": "B", "text": "The range from which the gun was fired was around 1 m.", "correct": false}, {"label": "C", "text": "The essential projectile element in this type of gun is pellets.", "correct": true}, {"label": "D", "text": "In this type of gun, the diameter is measured by the distance between two opposite lands.", "correct": false}], "correct_answer": "C. The essential projectile element in this type of gun is pellets.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891735536-QTDF008004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>The essential projectile element in this type of gun is pellets. In the given question, the type of firearm used in this is a shotgun. In a short gun, the cartridge consists of pellets and not bullets.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. It is a wound caused by a shotgun, but it is not rifled. Hence option A is wrong because the rifled weapon doesn’t cause multiple-entry wounds.. Option: B. The range from which the gun was fired was from 2-4 m and not 1m, as it is an intermediate range shot. So, option B is wrong. Option: D. The diameter of this type of firearm is measured with the help of the no of pellets of lead of same size which can be formed from 1 pound. The above definition in option D represents diameter of rifled firearm.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "While reading the chapter on forensic ballistic, you came across the following figure as given below. What are this phenomenon known as, and what is its advantage?", "options": [{"label": "A", "text": "Rifling- it provides the advantage of spinning effect to the projectile.", "correct": false}, {"label": "B", "text": "Musket- the end of the firearm is narrowed to provide it with more compactness.", "correct": false}, {"label": "C", "text": "Choking- narrowing the gun's terminal part to improve the pellets' velocity and explosive power.", "correct": true}, {"label": "D", "text": "None of these.", "correct": false}], "correct_answer": "C. Choking- narrowing the gun's terminal part to improve the pellets' velocity and explosive power.", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682891736711-QTDF008005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Choking- narrowing the gun's terminal part to improve the pellets' velocity and explosive power. In the given image, the terminal part of the gun is narrowed. This is known as choking. It offers the following advantages- Choking lessens the rate of spread of the shot after it leaves the muzzle. Increases the explosive force and increases the velocity</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Rifling provides the advantage of a spinning effect to the projectile, which is correct for rifled firearms. Rifling refers to the arrangement of spiral grooves inside the rifle barrel. Option: B. Musket- it is a military shoulder arm. It has a long forestock usually takes a bayonet (pointed knife-like weapon) at the muzzle. This image does not depict it.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The cartridge of shotguns is unique in the sense they consist of wads. Wads offer the following advantage-", "options": [{"label": "A", "text": "Provide compact packing to the pellet and the gunpowder compartment.", "correct": false}, {"label": "B", "text": "Prevent the leakage of gases so that they can act as a piston.", "correct": false}, {"label": "C", "text": "Prevent shock absorption or cushion.", "correct": true}, {"label": "D", "text": "Prevent the leakage of heat or transfer to the pellet compartment.", "correct": false}], "correct_answer": "C. Prevent shock absorption or cushion.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Prevent shock absorption or cushion. The cartridge of the shotgun consists of the wad, which is made up of cork material or plastic. Wad acts as a cushion or shock absorber. So, wad doesn’t prevent shock absorption.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Provide compact packing of the pellet and the gunpowder compartment. Option: B. Prevent the leakage of gases so that they can act as a piston. Option: D. Prevent the leakage of heat or transfer to the pellet compartment. Cardboard is placed between it and the gunpowder and the pellet compartment to prevent its entry into either compartment.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You were posted in an emergency when a 45 year old male was brought by a passer by as he has suffered gunshot injury. The patient was vitally unstable and was managed by resuscitation. You have called a forensic medicine expert to evaluate the wound. He, after examining explains to you that the wound explains a greater range of firing than it was. In which phenomena does this happens?", "options": [{"label": "A", "text": "Welding of shot", "correct": false}, {"label": "B", "text": "Billiard ball effect", "correct": true}, {"label": "C", "text": "Internal ricochet", "correct": false}, {"label": "D", "text": "None of the above.", "correct": false}], "correct_answer": "B. Billiard ball effect", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Billiard ball effect In the given question, as described, the range of the shot appeared to be more than the This occurs in billiard ball ricochet phenomena. At close range, while the shots are bunched, they strike one another upon impact on the primary target, i.e., the skin or clothes, and spread out in a wide pattern as they pass through the body. This causes the shot to spread widely and may suggest a greater range of fire than occurred.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Welding of the ball- Balling of shotgun pellets results in the conversion of the shot into a compact mass, which can travel for a few meters in this form. In such cases, a circular or oval entrance wound of about 5 to 10 mm. in diameter and widespread, small, circular punctures are seen, suggesting the use of two different weapons, one a shotgun at a distant range and the other a rifle. Option: C. Internal ricochet occurs when a bullet, rather than exiting the body, gets deflected and forms a new track inside the body. This doesn’t increase the range of firing.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A lady was brought with multiple injuries over the body to the emergency room. The attending doctor took some photographs. Choose the correct one:", "options": [{"label": "A", "text": "This is called periorbital bruising", "correct": false}, {"label": "B", "text": "It’s called ectopic bruising", "correct": false}, {"label": "C", "text": "It’s a migratory contusion", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892998902-QTDF045001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above All the above-mentioned statements are correct. Ectopic bruising/ Percolated /Migratory contusion:- Blood will track along the fascial planes (or between muscle layers) which form the least resistance and may appear where the tissue layers become superficial. Hemorrhages in the soft tissues around the eyes and the eyelids (spectacle hematoma; black eye), may be caused by Direct trauma, such as a punch in the eye Blunt impact to the forehead, the blood gravitating downwards over the supraorbital bridge Fracture of the floor of the anterior fossa of the skull. A bruise behind the ear may indicate a basal fracture, rather than a direct blow behind the ear.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person wanted to end his life. He decided to fall from the balcony of his apartment which was on the 10th floor. His skull Image looked similar to the Image shown below. It is a:", "options": [{"label": "A", "text": "Fissured fracture", "correct": false}, {"label": "B", "text": "Comminuted fracture", "correct": true}, {"label": "C", "text": "Pond fracture", "correct": false}, {"label": "D", "text": "Indented fracture", "correct": false}], "correct_answer": "B. Comminuted fracture", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892999557-QTDF045002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Comminuted fracture In a comminuted fracture, there are two or more intersecting lines of fracture that divide the bone into three or more fragments. They are caused by a significant force striking over a broad area, such as crushing head injuries, vehicle accidents, falls from a height on a hard surface, and from repeated blows by weapons with a large striking surface, e.g., heavy iron bar or poker, an axe, thick stick, etc. They may also result from a kick by an animal or by a bullet. It is often a complication of fissured or depressed fracture. When there is no displacement of the fragment, it resembles a spider's web or mosaic. Fissured fractures may radiate for varying distances from the area of comminution (fragmentation). When the force is great, the broken pieces of bone are displaced and some may enter the brain and others may be lost</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Fissured Fractures: They are produced by general deformation of the skull. These are linear fractures involving the whole thickness of the bone or inner or outer table only. Options: C & D. Pond fracture:-Pond or Indented Fractures: This is a simple dent of the skull</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A pediatrician examining a newborn baby notices a small dent on the scalp. He attributes the dent formation due to the usage of forceps during the delivery of the baby by the obstetrician. What is the dent which he is referring to?", "options": [{"label": "A", "text": "Pond fracture", "correct": false}, {"label": "B", "text": "Indented fracture", "correct": false}, {"label": "C", "text": "Gutter fracture", "correct": false}, {"label": "D", "text": "Both A and B", "correct": true}], "correct_answer": "D. Both A and B", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both A and B Pond or Indented Fractures:- This is a simple dent of the skull, which results from an obstetric forceps blade, a blow from a blunt object, or forcible impact against some protruding object. They occur only in the skulls of infants. The inner table is not fractured, but fissured fractures may occur in the outer table around the periphery of the dent. The dura mater is not torn and usually, the brain is not damaged. In an infant, a blow often produces only a dent, like that seen in a Ping-Pong ball.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: C. Gutter Fractures: They are formed when part of the thickness of the bone is removed to form a gutter, e.g., in oblique bullet wounds. They are usually accompanied by irregular, depressed fracture of the inner table of the skull. The dura mater and brain may be torn</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The consultant was teaching the students about different skull fractures. With reference to the given Image, pick the incorrect statement:", "options": [{"label": "A", "text": "It’s called a ring fracture", "correct": false}, {"label": "B", "text": "A forceful blow on the chin in a traffic accident may produce a ring fracture", "correct": false}, {"label": "C", "text": "Mandible is definitely fractured", "correct": true}, {"label": "D", "text": "Also called foramen magnum fracture", "correct": false}], "correct_answer": "C. Mandible is definitely fractured", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892999787-QTDF045004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mandible is definitely fractured The above statement is incorrect as the mandible is not always fractured in such cases. Ring or Foramen Fractures: (Option A and D): It is fissured fracture which encircles the skull in such a manner that the anterior third is separated at its junction with the middle and posterior third. But usually, the term is applied to a fracture, which runs at about 3 to 5 outside the foramen magnum at the back and sides of the skull and passes forwards through the middle ears and roof of the nose, due to which the skull is separated from the spine. They are rare and occur after falls from a height onto the feet or buttocks. In very severe cases, the spine may be driven into the skull cavity, and the vault of the skull may burst open (explosive type), giving the impression of an original massive fracture. (Option B) A severe blow to the vertex may also cause a ring fracture, but in this case, the fracture of the vault will be depressed. A forceful blow on the chin in a traffic accident may produce a ring fracture. There may be a laceration of skin, but the mandible is not fractured in most cases. They are thought to be produced from forces transmitted into the back of the skull through the mandibular joints. They are also caused by a sudden violent turn of the head on the spine, shearing the vault from the base.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A young man was walking back from the bus stop to his home at 11 PM. An unknown man hits the young man on his head, snatches his phone, and leaves the place. He was later taken to a hospital by a passerby. The given Image resembles the x-ray of the young man. Identify", "options": [{"label": "A", "text": "Diastatic fracture", "correct": true}, {"label": "B", "text": "Expressed fracture", "correct": false}, {"label": "C", "text": "Ring fracture", "correct": false}, {"label": "D", "text": "Perforating fracture", "correct": false}], "correct_answer": "A. Diastatic fracture", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893000402-QTDF045005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Diastatic fracture Diastatic or Sutural Fractures : Separation of the sutures occurs only in young persons, due to a blow on the head with a blunt It may occur alone but often is associated with fracture. It is usually seen in the sagittal suture. They also occur secondary to increased intracranial pressure with the resulting splitting of sutures.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Expressed fractures : These occur as massive fragmentation and shattering of the skull, where some pieces may be found outside the head. They occur due to massive trauma often involving contact or close-range firearm injuries or due to bomb blasts. Option: C. Ring or Foramen Fractures: It is fissured fracture which encircles the skull in such a manner that the anterior third is separated at its junction with the middle and posterior third. But usually, the term is applied to a fracture, which runs at about 3 to 5 cm. outside the foramen magnum at the back and sides of the skull and passes forwards through the middle ears and roof of the nose, due to which the skull is separated from the spine. Option: D. Perforating Fractures: These are caused by firearms and pointed sharp weapons like daggers or knives and axe. The weapon passes through both tables of the skull leaving more or less a clean-cut opening, the size and shape of which corresponds to the cross-section of the weapon used.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A motorcyclist was involved in a road mishap and died on spot. Identify the fracture shown in the Image", "options": [{"label": "A", "text": "Diastatic fracture", "correct": false}, {"label": "B", "text": "Comminuted fracture", "correct": false}, {"label": "C", "text": "Hinge fracture", "correct": true}, {"label": "D", "text": "Ring fracture", "correct": false}], "correct_answer": "C. Hinge fracture", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893000877-QTDF045006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hinge fracture Basal fractures tend to run along the petrous ridges through the sella turcica (Hinge Fractures). Hinge fractures are usually associated with injuries of the brainstem, particularly ponto-medullary.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B, & D. Diastatic fractures, comminuted fractures, or ring fractures are not related to motorcyclist road mishap. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A victim of a road mishap was sent for CT head. The below Image is representative of:", "options": [{"label": "A", "text": "Hinge fracture", "correct": false}, {"label": "B", "text": "Diastatic fracture", "correct": true}, {"label": "C", "text": "Ring fracture", "correct": false}, {"label": "D", "text": "Gutter fracture", "correct": false}], "correct_answer": "B. Diastatic fracture", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893001217-QTDF045007IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Diastatic fracture Diastatic or Sutural Fractures: Separation of the sutures occurs only in young persons, due to a blow on the head with a blunt It may occur alone but often is associated with fracture. It is usually seen in the sagittal suture. They are particularly common in traffic accidents. They also occur secondary to increased intracranial pressure with the resulting splitting of sutures.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Hinge fracture Basal fractures tend to run along the petrous ridges through the sella turcica (Hinge Fractures). Hinge fractures are usually associated with injuries of the brainstem, particularly ponto-medullary Option: C. Ring or Foramen Fractures: It is fissured fracture which encircles the skull in such a manner that the anterior third is separated at its junction with the middle and posterior third. Option: D. Gutter Fractures: They are formed when part of the thickness of the bone is removed to form a gutter, e.g., in oblique bullet wounds. They are usually accompanied by irregular, depressed fractures of the inner table of the skull. The dura mater and brain may be torn</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was hit by a hammer during an assault. There were multiple fractures on the head along with a signature fracture. Signature fracture mean?", "options": [{"label": "A", "text": "Suture displacement fracture", "correct": false}, {"label": "B", "text": "Depressed skull fracture", "correct": true}, {"label": "C", "text": "Contrecoup injury", "correct": false}, {"label": "D", "text": "Fracture at foramen magnum", "correct": false}], "correct_answer": "B. Depressed skull fracture", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Depressed skull fracture Depressed Fractures: They are produced with an object having a relatively large amount of kinetic energy but a small surface area, or when an object with a large amount of kinetic energy impacts only a small area of the skull. They are produced by local deformation of the skull. In this, the fractured bone is driven inwards into the skull cavity. The outer table is driven into the diploe, the inner table is fractured irregularly and to a greater extent and may be comminuted. They are also called \"fractures an Ia signature\" (signature fractures), as their pattern often resembles the weapon or agent which caused it.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Diastatic or Sutural Fractures: Separation of the sutures occurs only in young persons, due to a blow on the head with a blunt It may occur alone but often is associated with fracture. It is usually seen in the sagittal suture. They are particularly common in traffic accidents. They also occur secondary to increased intracranial pressure with the resulting splitting of sutures. Option: C. Contrecoup Injury- Injury occurring opposite to the impact of injury in the brain is known as contrecoup Option: D. Foramen Fractures: It is a fissured fracture that encircles the skull in such a manner that the anterior third is separated at its junction with the middle and posterior third. But usually, the term is applied to a fracture, which runs at about 3 to 5 cm. outside the foramen magnum at the back and sides of the skull and passes forwards through the middle ears and roof of the nose, due to which the skull is separated from the spine.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was brought to the emergency with a head injury. He was referred for a CT scan. The most common type of skull fracture is:", "options": [{"label": "A", "text": "Depressed", "correct": false}, {"label": "B", "text": "Fissured", "correct": true}, {"label": "C", "text": "Comminuted", "correct": false}, {"label": "D", "text": "Contre-coup", "correct": false}], "correct_answer": "B. Fissured", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Fissured Fissured Fractures are the most common type. They are produced by general deformation of the skull. These are linear fractures involving the whole thickness of the bone or inner or outer table only. About 70% of skull fractures are linear. The outer table is capable of rebounding to its normal shape, while the more brittle inner table fractures. It may be present alone or associated with other types.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Depressed Fractures: They are produced with an object having a relatively large amount of kinetic energy but a small surface area, or when an object with a large amount of kinetic energy impacts only a small area of the skull. They are produced by local deformation of the skull Option: C. Comminuted Fractures: In a comminuted fracture there are two or more intersecting lines of fracture that divide the bone into three or more fragments Option: D. Contrecoup Injury- Injury occurring opposite to the impact of injury in the brain is known as countercoup injuries.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Pond fracture is usually seen in:", "options": [{"label": "A", "text": "Adolescent", "correct": false}, {"label": "B", "text": "Infants", "correct": true}, {"label": "C", "text": "Adult", "correct": false}, {"label": "D", "text": "Old age", "correct": false}], "correct_answer": "B. Infants", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Infants Pond or Indented Fractures: This is a simple dent of the skull, which results from an obstetric forceps blade, a blow from a blunt object, or forcible impact against some protruding object. They occur only in the skulls of infants. The inner table is not fractured, but fissured fractures may occur in the outer table around the periphery of the dent. The dura mater is not torn and usually, the brain is not damaged. In an infant, a blow often produces only a dent, like that seen in a Ping-Pong ball.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C, & D. Pond Fractures are seen exclusively in infants. Hence adolescents, adults, or old age are not relevant to this question.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "If the head of the Snake has small scales covering the whole surface of head, as shown in the image below it indicates it is: (Illustration)", "options": [{"label": "A", "text": "Viper", "correct": true}, {"label": "B", "text": "Krait", "correct": false}, {"label": "C", "text": "Cobra", "correct": false}, {"label": "D", "text": "Non-poisonous", "correct": false}], "correct_answer": "A. Viper", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682894005628-QTDF076001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Viper VIPER OR DABOIA ( Kander, charn viper, khadchitro) has a flat, heavy and triangular head with a white V-shaped mark, the angle of the V pointing forwards. It has three rows of diamond-shaped black or brown spots along the back, the outer two rows consisting of spots ringed with white edges. Its body is whitish with dark semilunar spots. It narrows towards its tail, which is short. It can be identified by the entire broad plates on the belly, the small scales on the head, and the shield beneath the tail divided into two rows. It is heard to hiss loudly and continuously.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Heera Lal’s 10-year-old child presented in casualty with a snakebite for six hours. On examination no systemic signs are found & lab investigations are normal except for localized swelling over the leg < 5 cm. The next step in management would be:", "options": [{"label": "A", "text": "Incision & suction of local swelling", "correct": false}, {"label": "B", "text": "I/V anti-venom serum", "correct": false}, {"label": "C", "text": "S/c anti-venom at local swelling", "correct": false}, {"label": "D", "text": "Observe the patient for progression of symptoms wait for anti-venom therapy", "correct": true}], "correct_answer": "D. Observe the patient for progression of symptoms wait for anti-venom therapy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Observe the patient for progression of symptoms wait for anti-venom therapy If a patient is brought after a few hours (4 to 6) of snake bite with mild local swelling and no systemic symptoms, he should be kept under observation for 24 hours, closely monitored for vital signs, cardiac system and oxygen saturation, given tetanus toxoid and discharged</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 10-year-old boy presented at casualty with a history of snake bites with a small bite mark. On examination no abnormality was detected and laboratory investigations show a normal report. The most appropriate management is", "options": [{"label": "A", "text": "IV polyvalent anti-snake venom serum", "correct": false}, {"label": "B", "text": "Incision and suction of the bite site", "correct": false}, {"label": "C", "text": "Hold anti-snake venom serum and observe the patient", "correct": true}, {"label": "D", "text": "Local subcutaneous anti-snake venom", "correct": false}], "correct_answer": "C. Hold anti-snake venom serum and observe the patient", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hold anti-snake venom serum and observe the patient If a patient is brought after a few hours (4 to 6) of snake bite with mild local swelling and no systemic symptoms, he should be kept under observation for 24 hours, closely monitored for vital signs, cardiac system and oxygen saturation, given tetanus toxoid and discharged</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Polyvalent anti-snake venom is prepared by hyper-immunizing horses against the venoms of", "options": [{"label": "A", "text": "Cobra, Russell’s viper, Common krait", "correct": false}, {"label": "B", "text": "Cobra, Russell’s viper, Common krait and Sea snakes", "correct": false}, {"label": "C", "text": "Cobra, Russell’s viper, Common Krait and Saw scaled viper", "correct": true}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "C. Cobra, Russell’s viper, Common Krait and Saw scaled viper", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cobra, Russell’s viper, Common Krait and Saw scaled viper Polyvalent anti-snake venom (PA V) is prepared by hyperimmunized horses against the venom of the four common poisonous snakes, i.e., cobra, common krait, Russell's viper and saw-scaled viper.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person presented with an embarrassing erection of a penis. He did not take any medicine but he was bitten by an insect. Priapism may be a presenting feature in the case of", "options": [{"label": "A", "text": "Viper bite", "correct": false}, {"label": "B", "text": "Cobra bite", "correct": false}, {"label": "C", "text": "Spanish fly bite", "correct": true}, {"label": "D", "text": "Spider bite", "correct": false}], "correct_answer": "C. Spanish fly bite", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Spanish fly bite Spanish fly/blister beetle redness and burning pain are produced after two to three hours followed by vesication. Taken internally, symptoms appear in half to two hours. There is a burning sensation in the mouth and throat, followed by pain in the stomach, nausea and vomiting of bloody mucus, severe thirst, and difficulty in swallowing and speech. Later a dull pain is felt in the loins, the urine is scanty and bloodstained, though there is an increased desire to pass urine. Priapism may occur; there is often tenesmus. Abortion occurs in pregnant women. In severe cases, the patient becomes prostrated, convulsions occur, and death may take place in a condition of coma.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A group of villagers brought the dead body of a 48-year-old male farmer who was working in his field. On taking history it was revealed that the farmer was bitten by a snake at his left ankle. They brought with them the body of the snake too which they had killed. You are the duty doctor and you have to identify which snake it is by looking at the external appearance of the dead snake. Which of the following option is correctly matched?", "options": [{"label": "A", "text": "A", "correct": true}, {"label": "B", "text": "B", "correct": false}, {"label": "C", "text": "C", "correct": false}, {"label": "D", "text": "D", "correct": false}], "correct_answer": "A. A", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682894005794-QTDF076006IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A There are 216 species of snakes in India, of which only 52 are poisonous. In India only 5 of them are dangerously poisonous to man- King Cobra; Common Cobra; Common Krait; Russell’s Viper; Saw Scaled Viper. Findings in poisonous snakes- Head scales in poisonous snakes are of variable sizes (Small, Large; having a pit between eye and nostril; without pit; third labial touching the eye and nasal shields, etc.). Large belly scales that cover the entire Fangs are hollow like hypodermic needles, 2 long fangs are present. Tail is compressed and usually, the snakes are nocturnal. Option: A. Cobra - It has a hood, which on the dorsal side often bears a double or single spectacle mark, but sometimes has an oval spot surrounded by an ellipse. Head scales are large and the third labial touches the eye and the nasal shield. The portion of the neck surrounding the spectacle mark is darker than the rest of the back and is often speckled with small golden spots. The hood can not be seen in a dead cobra, as the joints and neck become stiff. The caudal scales are double. There is a white band in the region where the hood touches the body region. The colour is brown or dark. It grows to a length of about two metres. Maxillary bone extends beyond the Poison fangs are followed by one or two small teeth.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option: B . Russel Viper - It has a flat, heavy and triangular head with a white V-shaped mark, the angle of the V pointing forwards. It has 3 rows of diamond-shaped black or brown spots along the back, the outer 2 rows consisting of spots ringed with white edges. Its body is whitish with dark semilunar spots, it narrows towards its tail which is short. It can be identified by the entire broad plates on the belly, the small scales on the head, and the shield beneath the tail divided into 2 rows. The middle row is Option: C . Common Krait - It is steel-blue, often shining and has single or double white bands across the back and a creamy white belly. Its length is one to one and a half metres. 4 shields are found on either side of the lower lip. The scales in the central row down the back are large and hexagonal. The tail is round, and plates under the tail like those on the belly are entire and not divided. It has single or double white bands all over its surface. Option: D . Banded Krait - It is one and a half to two metres in length. The tail ends bluntly and is swollen at the tip. It has a jet black five cm wide cross band alternating with a deep yellow band of the same size on its back. There is a black mark on the neck which is spread up to the eyes. The scales are hexagonal.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "There are more than 3500 species of snakes, but only about 250 are venomous. In India only there are around 54 poisonous species. As an intern, you witnessed a case of snake bite brought to the casualty of your hospital. Which of the following are correctly matched to the families of the poisonous snakes? Viperidae - Saw scaled viper, Puff adder. Crotalidae - Rattlesnake, Copperhead. Elapidae - Boomslangs, Bird Snake. Hydrophidae - Water Moccasins. Colubridae - Cobras, Mambas. Atractaspididae - Stiletto snakes. Select the correct answer from the given below code:", "options": [{"label": "A", "text": "1,2,6", "correct": true}, {"label": "B", "text": "2,3,5", "correct": false}, {"label": "C", "text": "4,5,6", "correct": false}, {"label": "D", "text": "1,3,6", "correct": false}], "correct_answer": "A. 1,2,6", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,2,6 In India 216 species of snakes, out of them 52 are poisonous. The most dangerous are known as the Big Five- Common Cobra; Common Krait; King Cobra; Russell’s Viper; Saw Scaled Viper. The most common poisonous snake is Common Krait. There are 5 families of poisonous snakes in India- Viperidae- Russel’s Viper, Gaboon viper, Saw scaled viper, and puff adder. They are found in all parts of the world except the Crotalidae- Rattlesnakes, Copperhead, Water moccasins, pit viper. They are found in swampy areas or along the banks of streams. It is a strong swimmer and can bite underwater. Elapidae- Cobras, Kraits, mambas, tiger snakes, taipan, coral snakes. Hydrophidae- Sea snakes. Colubridae- Boomslangs, bird snakes. Atractaspididae- African and Middle Eastern burrowing asps, stilleto snakes. Elapidae are neurotoxic, Vipers are Vasculotoxic. S.NO Trait Poisonous snakes Non-poisonous snakes (1) Head scales: (1) Small (vipers). (2) Large, and (a) if there is an opening or pit between the eye and nostril (pit viper). (b) Third labial touches the eye and nasal shields (cobra or coral snake). (c) No pit and the third labial does not touch the nose and eye and the central row of scales on the back is enlarged; the undersurface of the mouth has only four infralabials, the fourth being the largest (kraits). Large with the exceptions as mentioned, under the poisonous snakes. (2) Belly scales: Large and cover the entire breadth. Small, like those on the back or moderately large, but do not cover the entire breadth. (3) Fungs: Hollow-like hypodermic needles. Short and solid. (4) Teeth: Two long fangs. Several small teeth. (5) Tail: Compressed. Not much compressed. (6) Habits: Usually nocturnal. Not so.</p>\n<p><strong>Random:</strong></p><p>Explanation for all options: - Option A. 1,2,6 are the correct examples of Viperidae, Crotalidae and Atractaspididae families of poisonous snakes. Option B . Elapidae- Cobras, Kraits, mambas, tiger snakes, taipan, coral snakes and Hydrophidae- Sea snakes are the correct matches for the families and not the ones given in option. Option C. Hydrophidae- Sea snakes and Colubridae- Boomslangs, bird snakes matches correctly to the options rather than the ones given in the Option D. Elapidae- Cobras, Kraits, mambas, tiger snakes, taipan, and coral snakes are the correct examples and not the ones that are given in the question.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 20-year-old boy was brought dead with a snake bite mark on his left ankle to the ER of a govt. hospital. The patient had symptoms of nausea, vomiting, and inability to stand or move and he complained of difficulty in breathing. No first aid was given to the patient and his 20 minutes blood clotting test was negative. Which of the following is a correct match for the type of poisoning he suffered from?", "options": [{"label": "A", "text": "Each vial of PAV neutralises about 6 to 8 mg of venom.", "correct": true}, {"label": "B", "text": "A pressure of 100 - 140 mm Hg is maintained by a bandage at the bite area known as Sutherland wrap.", "correct": false}, {"label": "C", "text": "The fatal period for Cobra is 1-2 days and for Viper is half to six hrs.", "correct": false}, {"label": "D", "text": "ELISA is the most sensitive and specific test and it can detect venom levels of 0.4ug/l.", "correct": false}], "correct_answer": "A. Each vial of PAV neutralises about 6 to 8 mg of venom.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Each vial of PAV neutralises about 6 to 8 mg of venom. There are about 216 species of snakes in India, but only 52 are poisonous. In India, there are only 5 varieties which are dangerously poisonous: Common Cobra; Common Krait; King Cobra; Russell's Viper; Saw scaled Viper. Cobra snake has a long and cylindrical body with a small head that is seldom broader than the body, covered by large scales or shields of special forms; Russel Viper has a flat, heavy and triangular head with a white V-shaped mark, the angle of the V pointing forwards. It has 3 rows of diamond-shaped black or brown spots along the back, the outer 2 rows consisting of spots ringed with white edges. Common Krait is steel-blue, often shining and has single or double white bands across the back and a creamy white belly. Its length is one to one and a half metres. 4 shields are found on either side of the lower lip. Venom is the saliva of the snake. Cobra venom is faint transparent yellow and is slightly viscous, when exposed to the sun it becomes turbid. Russel’s viper venom is white or yellow. The fatal period for Cobra is half to six hrs; for Viper is 1-2 days. For diagnosis, snake-specific venom antigens are detected in wound swabs, serum, biopsies, urine etc. along with the underlying tissue and skin of the bite mark; RIA(Radioimmunoassay) is the most sensitive and specific test and it can detect venom levels of 0.4ug/l; enzyme immunoassay (EIA) is commonly used as it is simple and can detect venom levels of 5ug/l; immunological detection of small amounts of venom antigens in body fluids can be done by ELISA. First aid- Assure the patient, and apply firm pressure over the bitten area which delays the absorption of venom. Pressure immobilisation is recommended by applying a broad firm bandage (Sutherland wrap), and the pressure of 50- 70 mm Hg is maintained. Cauterisation, Cryotherapy and sucking of venom through the mouth should not be done. Treatment- PAV (Polyvalent Antisnake Venom) is used which is prepared by hyper-immunising horses against the venom of 4 snakes only- Cobra; Common krait; Russell’s Viper; Saw scaled viper. Option: A. Polyvalent Antisnake Venom is made by hyper immunising horse against venom and obtaining the plasma and purifying it. Each vial of PAV will neutralise about 6-8 mg of venom.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option: B. A pressure of 50-70 mm Hg is maintained by a broad and firm bandage at the bite area known as Sutherland wrap. Option: C. The fatal period for Cobra is half to six hrs; for Viper is 1-2 days. Venom in Cobra is neurotoxic. Option: D. RIA(Radioimmunoassay) is the most sensitive and specific test and it can detect venom levels of 0.4ug/l.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 15-year-old girl who went for defecation in the fields early morning fell unconscious after the bite mark as shown in the image on her ankle. She had difficulty breathing along with excess salivation and drooping of the eyelids. On taking her to the nearby PHC she was declared dead and her autopsy was done. Which of the following PM findings are true for this type of poisoning?", "options": [{"label": "A", "text": "Poisonous snakes leave multiple bite marks in the form of a semicircular pattern.", "correct": false}, {"label": "B", "text": "ELISA cannot identify the nature of venom from the bite site.", "correct": false}, {"label": "C", "text": "In viper bite, there is discolouration, swelling and cellulitis above the mark and haemorrhage occurs from the puncture and mucous membranes.", "correct": true}, {"label": "D", "text": "CNS damage is the leading cause in case of a viper bite.", "correct": false}], "correct_answer": "C. In viper bite, there is discolouration, swelling and cellulitis above the mark and haemorrhage occurs from the puncture and mucous membranes.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>In viper bite, there is discolouration, swelling and cellulitis above the mark and haemorrhage occurs from the puncture and mucous membranes. It was a case of Snake bite poisoning as indicated by the image and the clinical features as mentioned in the case scenario. Poisonous snakes leave 2 or occasionally one fang mark; Non-poisonous snakes leave a semicircular set of tooth marks. The punctures are one and a half cm deep in colubrine and two and a half cm deep in viperine bites. For diagnosis, snake-specific venom antigens are detected in wound swabs, serum, biopsies, urine etc. along with the underlying tissue and skin of the bite mark; RIA(Radioimmunoassay) is a most sensitive and specific test and it can detect venom levels of 0.4ug/l; enzyme immunoassay (EIA) is commonly used as it is simple and can detect venom levels of 5ug/l; immunological detection of small amounts of venom antigens in body fluids can be done by ELISA. More than 50% of the victims of Viper Bites have minimal or no poisoning, as little or no venom is injected. About 25% will develop serious generalised poisoning. When venom is injected, the spot develops severe pain within 8 minutes. The onset of swelling starts within fifteen minutes and there is often blood-stained discharge from the wound. Blisters begin to appear in about 12hrs in and around the bite site, progressing subsequently to involve the entire limb. In a colubrine bite, the site of the bite contains fluid and haemolysed blood causing staining of vessels. In viperine bite, there is discolouration, swelling and cellulitis about the mark and haemorrhages occur from the puncture and mucous membranes. Haemorrhages into the bowel, purpuric spots on the pericardium, and haemorrhages in the lungs and in many tissues may be seen. Kidneys are inflamed and show marked congestion. Subcapsular pinpoint haemorrhages are seen in most cases of viperine bite. Acute renal failure is the leading cause of death in viper bite. Internal organs are congested. Washing from the bite area may contain cholinesterase or thromboplastin. The skin and underlying tissue surrounding fang marks should be removed for analysis. ELISA (enzyme-linked immunosorbent assay) can identify the nature of venom from the bite site.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option A. Poisonous snakes leave 2 or occasionally one fang mark; Non-poisonous snakes leave a semicircular set of tooth marks. Option B. ELISA (enzyme-linked immunosorbent assay) can identify the nature of venom from the bite site as immunological detection of small amounts of venom antigens in body fluids can be done by ELISA. Option D. Acute renal failure is the leading cause of death in viper bite. Internal organs are congested.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A snake bite case was reported at your PHC, the patient was anxious and had symptoms like nausea, vomiting, anxiety and the bite mark resembled the image given below. You declared it to be a non-poisonous snake. Which of the following are correctly matched with the options given below? Cobra-Ptosis is the commonest and earliest manifestation. Krait - Nausea and froth are present, but no drowsiness. Viper - Local necrosis is extensive which may lead to gangrene. Sea snake - The bite is usually painful with extensive swelling and involvement of lymph nodes. A normal 20 WBCT and clot lysis would exclude Viperidae species. A single breath counting test is done in suspected Viperidae bites. Select the correct answer from the given below code:", "options": [{"label": "A", "text": "1,3,5", "correct": true}, {"label": "B", "text": "2,4,6", "correct": false}, {"label": "C", "text": "1,2,4", "correct": false}, {"label": "D", "text": "3,4,5", "correct": false}], "correct_answer": "A. 1,3,5", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682894007197-QTDF076010IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,3,5 The case is the bite of a non- poisonous snake as indicated by the image of the bite mark. Poisonous snakes leave 2 or occasionally one fang mark; Non-poisonous snakes leave a semicircular set of tooth marks. The punctures are one and a half cm deep in colubrine and two and a half cm deep in viperine bites. Cobra snake has a long and cylindrical body with a small head that is seldom broader than the body, covered by large scales or shields of special forms; Russel Viper has a flat, heavy and triangular head with a white V-shaped mark, the angle of the V pointing forwards. It has 3 rows of diamond-shaped black or brown spots along the back, the outer 2 rows consisting of spots ringed with white edges. Cobra- the local symptoms start within 6-8 minutes; a small reddish wheal develops at the site of the bite. The bitten area is tender with a burning pain. Early symptoms include nausea and vomiting. The patient feels sleepy, and intoxicated, has weakness in his legs, and is reluctant to move or stand. Ptosis is the earliest neuroparalytic manifestation followed by ophthalmoplegia, extraocular weakness and strabismus are seen. Paralysis spreads from the lower limbs to the trunk and then to the head. Krait signs and symptoms are similar to cobra poisoning, there is no nausea and froth, but drowsiness is more. Viper- More local reaction is seen along with pain and oozing, local necrosis is extensive which may lead to gangrene. Bilateral parotid swelling (Viper head), conjunctival edema and subconjunctival haemorrhages are seen. Sea snake- The bite is usually painless with minimal or no local swelling or involvement of local lymph nodes. Generalised rhabdomyolysis occurs. 20 min whole blood clotting test (20 WBCT): This is a very useful and informative bedside test. Place a few ml of freshly sampled venous blood in a clean, dry, glass tube/bottle. Leave it undisturbed for 20 min at room temperature. Gently invert the tube. If the blood is still unclotted and runs out, the patient has hypofibrinogenemia as a result of venom-induced consumption coagulopathy. A normal 20 WBCT and clot lysis would exclude Viperidae species. A single breath counting test is done in suspected elapidae bites, and the same is repeated at 15 min intervals over the first 2 h.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option B. Krait, sea snake and single breath counting test are wrongly matched to their explanations. Option C. Krait and the sea snake are wrongly matched to their explanations. Option D. Sea snake- The bite is usually painless with minimal or no local swelling or involvement of local lymph nodes is the correct explanation which is not given.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A case of poisoning was declared dead at an emergency. Interestingly, the core body temperature of the person did not drop even after 2 hours. Postmortem caloricity is seen in:", "options": [{"label": "A", "text": "Strychnine poisoning", "correct": true}, {"label": "B", "text": "Organophosphorus poisoning", "correct": false}, {"label": "C", "text": "Dhatura poisoning", "correct": false}, {"label": "D", "text": "Ergot poisoning", "correct": false}], "correct_answer": "A. Strychnine poisoning", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Strychnine poisoning Postmortem Caloricity: In this condition, the temperature of the body remains raised for the first two hours or so after death. This occurs: When the regulation of heat production has been severely disturbed before death, as in sunstroke and some nervous disorders When there has been a great increase in heat production in the muscles due to convulsions, as in tetanus and strychnine poisoning, etc., and When there has been excessive bacterial activity, as in septicaemic conditions cholera and other fevers</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "In poisoning due to the below-seen seeds, the chief symptom is", "options": [{"label": "A", "text": "Convulsions", "correct": true}, {"label": "B", "text": "Diarrhea", "correct": false}, {"label": "C", "text": "Cardiac arrhythmia", "correct": false}, {"label": "D", "text": "Salivation and urination", "correct": false}], "correct_answer": "A. Convulsions", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682894032996-QTDF077004IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Convulsions The seeds are of nux vomica and the active component is strychnine Strychnine inhibits postsynaptic glycine receptors predominantly in the spinal cord, causing involuntary painful skeletal muscle contractions. Patients present with “awake seizures\" which are episodic muscle contractions with no post-ictal period and normal mental status</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 12 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "With reference to the given Image, pick the wrong statement", "options": [{"label": "A", "text": "It is a penetrating wound", "correct": true}, {"label": "B", "text": "Through-and-through puncture wounds are produced", "correct": false}, {"label": "C", "text": "The wound of entry is larger with inverted edges, and the wound of exit is smaller with everted edges due to the tapering of the blade", "correct": false}, {"label": "D", "text": "The victim of injury may not show signs and symptoms until many hours have passed", "correct": false}], "correct_answer": "A. It is a penetrating wound", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892649802-QTDF034001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>It is a penetrating wound The given image shows perforating injury.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B: Perforating wounds or through-and-through puncture wounds are produced. Option C: The wound of entry is larger with inverted edges, and the wound of exit is smaller with everted edges due to the tapering of the blade. Option D: The victim of a fatal penetrating injury may not show signs and symptoms of injury until many hours have passed. (Option D)</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A postgraduate surgery student tried to put a chest tube in a patient in ER, for which he had to create a wound. What are these wounds called?", "options": [{"label": "A", "text": "Traumatic wound", "correct": false}, {"label": "B", "text": "Therapeutic wound", "correct": true}, {"label": "C", "text": "Unintentional wound", "correct": false}, {"label": "D", "text": "Unexpected wounds", "correct": false}], "correct_answer": "B. Therapeutic wound", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Therapeutic wound Therapeutic Wounds : These are wounds produced by doctors during the treatment of a patient, such as surgical stab wounds of the chest for insertion of chest tubes, of the abdomen for drains, thoracotomy and laparotomy incisions, incisions on the wrists, antecubital fossae and ankles, and tracheostomy incisions. Some of these wounds may be mistaken for traumatic wounds, e.g. a surgical chest stab wound for putting a drainage tube. Sometimes, a traumatic wound may be enlarged and included in the surgical procedure, or a drainage tube may be put in a homicidal stab wound.</p>\n<p><strong>Random:</strong></p><p>Explanation For incorrect Options:- Options A, C & D: Wounds intentionally created by a doctor are therapeutic wounds and never traumatic, unintentional or unexpected. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The Image shown below helps determine", "options": [{"label": "A", "text": "Death due to hanging", "correct": false}, {"label": "B", "text": "Gaping in stab wounds", "correct": true}, {"label": "C", "text": "Postmortem change after 5 days", "correct": false}, {"label": "D", "text": "Injury to internal organs in penetrating wound to the body", "correct": false}], "correct_answer": "B. Gaping in stab wounds", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682892650081-QTDF034003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Gaping in stab wounds Cleavage lines of Langer: Stab and incised wounds are slit-shaped with two acute angles or gape open depending on their location and orientation, about the so-called cleavage lines of Langer. The pattern of fibre arrangement of the dense feltwork of intimately intermingled dermal collagen and elastic fibres is called the cleavage direction or lines of cleavage of the skin. Their linear representation on the skin is called. Langer's lines are almost the same in all persons. Cleavage lines in the dermal layers of skin are primarily arranged in parallel rows. The extremities tend to run longitudinally, in the neck and trunk circumferentially. A stab wound which runs parallel to the cleavage lines will remain slit-shaped and narrow, and the dimensions of the blade will be represented with considerable accuracy.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options A, C & D: The above image shows Lines of Langer, unrelated to death due to hanging, postmortem changes or internal organ injuries. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A stab wound on the body of the deceased was peculiar in appearance. Fishtailing of margins in stab wounds is seen with :", "options": [{"label": "A", "text": "Single-edged knife", "correct": true}, {"label": "B", "text": "Double-edged knife", "correct": false}, {"label": "C", "text": "Bayonet", "correct": false}, {"label": "D", "text": "None", "correct": false}], "correct_answer": "A. Single-edged knife", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Single-edged knife If a single-edged weapon is used, the surface wound will be triangular or wedge-shaped, and one angle of the wound will be sharp, the other rounded, blunt or squared off. The blunt end of the wound may have small splits in the skin at each end of the corner, so-called \"fishtailing\" if the back edge of the blade is stout.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C & D. Fishtailing is usually seen in a single-edged knife, not a bayonet or a double-edged knife(elliptical-shaped wound). Hence these options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person who recovered completely burnt from a house had multiple incised-looking wounds over his head. The difference between heat rupture and incised wound, favouring heat ruptures, are:", "options": [{"label": "A", "text": "Margins well defined", "correct": false}, {"label": "B", "text": "Small and multiple wounds", "correct": false}, {"label": "C", "text": "Nerves and vessels visible in the floor", "correct": true}, {"label": "D", "text": "Seen over the scalp", "correct": false}], "correct_answer": "C. Nerves and vessels visible in the floor", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Nerves and vessels visible in the floor Intact vessels and nerves are seen on the floor. Heat Ruptures: In severe burning or charring skin contracts, heat ruptures occur before or after death.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option B: These ruptures or splits in the skin may be several centimetres long; superficially, they may resemble lacerations or even incised wounds. Option D: They are produced by splitting the soft part. These splits may be anywhere but are usually seen over fleshy body areas, like calves, thighs and extensor surfaces, joints and on the head. Splits of abdominal walls occur parallel to muscle fibres. They can be differentiated by: The bleeding in the wound and surrounding tissues is absent since heat coagulates the blood in the vessels. Option A: Irregular margins. Absence of bruising or other signs of a strong reaction in the margins. The underlying muscle usually ruptures due to heat when the skin is completely burnt.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A 16-year-old boy died due to an electric shock while playing near an electric post. His body was disfigured due to the high voltage. Permanent impairment of fingerprint pattern occurs in?", "options": [{"label": "A", "text": "Leprosy", "correct": false}, {"label": "B", "text": "Electric injury", "correct": false}, {"label": "C", "text": "Exposure to radiation", "correct": false}, {"label": "D", "text": "All the above", "correct": true}], "correct_answer": "D. All the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All the above Ridge alteration occurs in eczema, acanthosis nigricans, scleroderma, and dry or atrophic skin. Permanent impairment of the fingerprint pattern occurs in leprosy. electric injury and after exposure to radiation. In infantile paralysis, rickets ,and acromegaly, though the pattern is not altered, the distance between the ridges can be changed.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A partial fingerprint was obtained from a crime scene at a hotel, the points of similarity for the identification of the killer should be at least?", "options": [{"label": "A", "text": "10", "correct": true}, {"label": "B", "text": "15", "correct": false}, {"label": "C", "text": "18", "correct": false}, {"label": "D", "text": "20", "correct": false}], "correct_answer": "A. 10", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>10 In practice, 10 to 12 points of fine comparison are accepted as proof of identity. The patterns are not inherited and paternity cannot be proved through fingerprint patterns. The pattern is different even in identical twins. The fingerprint patterns are distinctive and permanent in individuals.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: B, C, & D. 15, 18, and 20 points of similarity are also accepted as proof of identity but the minimum requirement is only 10. Hence are not correct options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "From a crime scene, chance impressions were obtained with no definite patterns of fingerprints, next study for identifying the killer is by?", "options": [{"label": "A", "text": "Poroscopy", "correct": true}, {"label": "B", "text": "Cheiloscopy", "correct": false}, {"label": "C", "text": "Locard’s method", "correct": false}, {"label": "D", "text": "Williams method", "correct": false}], "correct_answer": "A. Poroscopy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Poroscopy The ridges on fingers and hands are studded with microscopic pores, formed by mouths of ducts of subepidermal sweat glands. Each millimetre of a ridge contains 9 to 18 pores. These pores are permanent and unchanged during their lifetime and vary in size, shape, width, starting, and stopping on occasion and branching at points, position, extent and number, distribution and arrangement of the pores over a given length of the ridge in each individual. This method of examining pores is called poroscopy and is useful when only fragments of fingerprints are available in which there is no specific pattern.</p>\n<p><strong>Random:</strong></p><p>Explanation for Incorrect Options:- Option: B. Cheiloscopy is the study of lip prints. It has nothing to do with impressions or fingerprints Option: C & D. William's and Locard's method is not related to chance impressions obtained from the crime scene in this question.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A film actress was found dead in the hotel room. The police suspect homicide on the primary analysis of the crime scene. While obtaining fingerprints from the suspects they found a suspect with burns all over the palm. Find the incorrect statement:", "options": [{"label": "A", "text": "Criminals attempt to mutilate fingerprints by self-inflicted wounds or burns", "correct": false}, {"label": "B", "text": "In the case of pre-death struggle, the fingerprints of the assailant will remain on the victim even before death", "correct": true}, {"label": "C", "text": "Fingerprints can be obtained from decomposed bodies", "correct": false}, {"label": "D", "text": "Permanent impairment of the fingerprint pattern is seen in leprosy, electric injury, and after exposure to radiation.", "correct": false}], "correct_answer": "B. In the case of pre-death struggle, the fingerprints of the assailant will remain on the victim even before death", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>In the case of pre-death struggle, the fingerprints of the assailant will remain on the victim even before death The fingerprint of the assailant will remain on the victim only after death. During the pre-death struggle, both the assailant and the victim will sweat due to nervous tension. After death, the victim will not sweat due to which fingerprints will be left on the body.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Criminals attempt to mutilate fingerprints by self-inflicted wounds or burns. Option: C. In advanced putrefaction and in cases of drowning, fingerprints can be obtained from the dermis after the epidermis is lost. Option: D. Permanent impairment of the fingerprint pattern is seen in leprosy, electric injury and after exposure to radiation.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A fetus was brought for a postmortem examination. The center of ossification of which one of the following is used as medicolegal evidence for fetal viability:", "options": [{"label": "A", "text": "Head of the femur", "correct": false}, {"label": "B", "text": "Distal end of femur", "correct": true}, {"label": "C", "text": "Greater trochanter", "correct": false}, {"label": "D", "text": "Lesser trochanter", "correct": false}], "correct_answer": "B. Distal end of femur", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Distal end of femur The centre of ossification for the lower end of the femur appears at 9 months, which is the age of maturity of the fetus and hence the best answer.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, C & D The upper-end of humerus- 1,3,5 yrs (head, gr. tuberosity, lesser tuberosity), Upper-end of Femur- 1,4,14 yrs (head, gr. Trochanter, lesser trochanter). Upper-end humerus- 1,3,5 yrs (head, gr. tuberosity, lesser tuberosity), Upper end Femur- 1,4,14 yrs (head, gr. Trochanter, lesser trochanter).</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 15 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A witness is summoned by both additional sessions court and assistant session court on the same day:", "options": [{"label": "A", "text": "He should attend the assistant session court first", "correct": false}, {"label": "B", "text": "Should attend the additional sessions of court first", "correct": true}, {"label": "C", "text": "He can write a letter to the sessions court stating that he can't attend either of the higher courts since he is summoned on the same day.", "correct": false}, {"label": "D", "text": "No need to attend either of the courts.", "correct": false}], "correct_answer": "B. Should attend the additional sessions of court first", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Should attend the additional sessions of court first He should attend additional sessions court first because additional sessions court is a higher court compared to assistant session court. Criminal Courts have priority over civil Courts. If a witness is summoned by two Courts on the same day, one of which is criminal and the other cities, he should attend the Criminal Court and inform the Civil Court of his inability to attend, giving his reasons. Higher Courts have priority over the lower. If he is summoned from two Courts of the same status, he must attend the Court from where he received the summons first, informing the other Court about it. He can attend the second Court after finishing his evidence in the first Court.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Since the assistant session court is a lower-ranked court than the additional sessions court, he can attend it only after the higher Court Option: C & D. It is an offence to not attend any court after getting a He has to attend the higher-ranked court for sure.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "For attending summon in criminal cases a witness may claim. Which of the following?", "options": [{"label": "A", "text": "Conduct money", "correct": false}, {"label": "B", "text": "Can’t claim any money", "correct": false}, {"label": "C", "text": "Conveyance charges & daily allowance", "correct": true}, {"label": "D", "text": "Both A & C", "correct": false}], "correct_answer": "C. Conveyance charges & daily allowance", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Conveyance charges & daily allowance In criminal cases, no fee is paid to the witness at the time of serving the summons. He must attend the Court and give evidence because of the interest of the State in securing justice; otherwise, he will be charged with contempt of Court. However, in criminal cases, conveyance charges and daily allowance can be claimed by the doctor according to Government rules.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Conduct money is the money given to a witness summoned to a civil court (and not criminal court) to meet his expenses to reach the court. Option: B. The witness is paid conveyance charges and daily allowance though he is not paid conduct money. Hence he can claim the</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A Police officer arrested a VCD shop owner who is accused of selling pirated copies of the latest Bollywood movies. A case was filed and the accused was presented before the Magistrate. At the court, the shop owner pleads not guilty. Then what will be the order of further proceedings : A date is fixed for the examination of the witnesses The prosecution evidence is recorded during which the accused is permitted to cross-examine the prosecution witness The defence evidence is recorded during which the prosecution is allowed to cross-examine the defence witness. Both sides' lawyers make oral arguments regarding the evidence. Conclusion regarding the guilt or innocence of the accused by the Magistrate. Select the correct answer from the given below code:", "options": [{"label": "A", "text": "A, D, C, B, E", "correct": false}, {"label": "B", "text": "A, C, B, D, E", "correct": false}, {"label": "C", "text": "A, D, B, C, E", "correct": false}, {"label": "D", "text": "A, B, C, D, E", "correct": true}], "correct_answer": "D. A, B, C, D, E", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>A, B, C, D, E The following are the proceedings if the accused pleads not guilty in warrant cases presented before the Magistrate (for charges OTHER THAN grave offences like rape, or murder) : A date is fixed for the examination of the witnesses The prosecution evidence is recorded during which the accused is permitted to cross-examine the prosecution witness The defence evidence is recorded during which the prosecution is allowed to cross-examine the defence witness. Both sides' lawyers make oral arguments regarding the evidence. Conclusion regarding the guilt or innocence of the accused by the Magistrate.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 13 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Unable to take care of their 4 children because of poor socioeconomic status, they take the youngest child aged 4 years to a place 100 km away from their home and leave her there. What will be the punishment to the couple if they are accused of abandoning their child?", "options": [{"label": "A", "text": "Imprisonment upto 3 years", "correct": false}, {"label": "B", "text": "Imprisonment upto 5 years", "correct": false}, {"label": "C", "text": "Imprisonment upto 7 years", "correct": true}, {"label": "D", "text": "Not punishable because they abandon the child because of their poor socioeconomic status", "correct": false}], "correct_answer": "C. Imprisonment upto 7 years", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Imprisonment upto 7 years Sec 317 IPC. Exposure and abandonment of a child under twelve years, by a parent or person having to care for it. Whoever being the father or mother of a child under the age of twelve years, or having the care of such child, shall expose or leave such child in any place with the intention of wholly abandoning such child, shall be punished with imprisonment of either description for a term which may extend to seven years, or with fine, or with both.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, B, & D. Imprisonment upto 3 and 5 years punishment is not the maximum punishment for abandoning a child</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A pregnant woman has 3 living girl children, and delivers a baby girl even in her fourth pregnancy. The couple kills the 5-day-old baby girl and disposes of it in a dustbin. It came to light when a stray DOG was carrying the dead baby in its mouth. Later a case was registered. The police could identify the accused, 2 days after the incident. Which of the following IPC section deal with this?", "options": [{"label": "A", "text": "Sec 317 IPC", "correct": false}, {"label": "B", "text": "Sec 318 IPC", "correct": true}, {"label": "C", "text": "Sec 319 IPC", "correct": false}, {"label": "D", "text": "Sec 320 IPC", "correct": false}], "correct_answer": "B. Sec 318 IPC", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sec 318 IPC CONCEALMENT OF BIRTH: Whoever, secretly buries or otherwise disposes of the dead body of a child, whether such child dies before or after or during its birth, intentionally conceals the birth of such child, shall be punished with imprisonment for up to two years. If the child whose dead body is so disposed is of a girl child, the person committing such offense shall be punished with rigorous imprisonment for a term which may extend to five years and shall also be liable to a fine which may extend to fifty thousand rupees (Sec. 318, I.P.C).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Sec 317 IPC. Exposure and abandonment of child under twelve years, by parent or person having to care of it.—Whoever being the father or mother of a child under the age of twelve year, or having the care of such child, shall expose or leave such child in any place with the intention of wholly abandoning such child, shall be punished with imprisonment of either description for a term which may extend to seven years, or with fine, or with both. Option: C. Sec 319 IPC Hurt.—Whoever causes bodily pain, disease, or infirmity to any person is said to cause hurt. Option: D. Sec 320 IPC. Grievous hurt.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 60-year-old woman lives alone in a house. Her children live abroad. She visits hospitals every now and then with varied types of complaints. She goes to the hospital with complaints of stomach pain and gets an ultrasound abdomen every time she visits the hospital. She goes from one hospital to another with similar complaints. This is", "options": [{"label": "A", "text": "Munchausen syndrome", "correct": true}, {"label": "B", "text": "Munchausen’s syndrome by proxy", "correct": false}, {"label": "C", "text": "Malingering", "correct": false}, {"label": "D", "text": "Both A and B", "correct": false}], "correct_answer": "A. Munchausen syndrome", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Munchausen syndrome MUNCHAUSEN'S SYNDROME: Munchausen syndrome is feigning illness or injury and going from hospital to hospital for unnecessary investigations and treatment. These patients appear to be compulsively driven to make their complaints. The person is aware that he/she is acting out an illness, but he cannot stop the act. There is continuity, ranging from exaggerated claims of infirmity to actual self-induced illness.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B & D. MUNCHAUSEN'S SYNDROME BY PROXY: This term is used to describe the actions of one person (usually a mother) who inflicts harm against another person (usually an infant or small child) in an attempt to gain sympathy and attention for both her own and her child's suffering. Option: C. MALINGERING: Malingering or shamming means conscious, planned feigning, or pretending a disease for the sake of gain. Diseases may be feigned for several reasons, such as by soldiers or policemen to avoid their duties, by prisoners to avoid hard work, by businessmen to avoid business contracts, by workmen to claim compensation, by beggars to attract public sympathy, by criminals to avoid legal responsibility, etc. The diseases that may be feigned are many, e.g., dyspepsia, intestinal colic, ulcers, spitting of blood, diabetes, rheumatism, and neurasthenia, aphasia, sciatica, pain in the back, blindness, deafness, vertigo, epilepsy, insanity, paralysis of the limbs, burns, artificial bruises, etc. Patients can distort or exaggerate their symptoms but true simulation is very rare: The patient may injure his nasopharynx with a sharp instrument, swallow the blood, and regurgitate it in front of the doctor to mimic hematemesis. A skillful puncturing of the anal or vaginal mucosa may produce bleeding. Excessive intake of digitalis may simulate a heart condition. Eating a large amount of carrots will produce carotenemia and may simulate jaundice. Chronic ingestion of coumarin will induce a hemorrhagic diathesis. In many cases detection is easy, but in some cases it is difficult. The history of the case should be taken from the person himself and his relatives or friend, and any inconsistencies in his description of the symptoms noted. Usually, the signs and symptoms do not conform to any known disease. Malingering can be diagnosed by keeping the patient under observation and watching him without his knowledge. A complete examination is essential after removing the bandages if any and washing the part. Rarely an anesthetic may be given to detect malingering.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An unresponsive 5-month-old male baby is brought by his mother to the hospital at around 5 AM She tells the doctor that the baby was fine when she last breastfed the baby but is totally unresponsive since morning. A case was registered. Even after a case investigation, reviewing the clinical history, and complete autopsy, the cause of death couldn’t be identified. This is:", "options": [{"label": "A", "text": "Sudden Infant Death Syndrome", "correct": false}, {"label": "B", "text": "Crib death", "correct": false}, {"label": "C", "text": "Cot death", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above SUDDEN INFANT DEATH SYNDROME :- Sudden infant death syndrome (SIDS), or cot death or crib death is defined as the sudden and unexpected death of a seemingly healthy infant, whose death remains unexplained even after thorough case investigation, death scene examination, review of clinical history and complete autopsy. Features: Incidence: 0.6 per thousand live births. Age: 2 weeks to 2 years, but most deaths take place between one and 7 months, with a peak at 2 to 4 months. Sex: There is a slight increase in males. Twins: There is an increased risk (threefold) amongst members of a twin pair. Most twins are premature and of low birth weight. Geographical distribution: The occurrence is worldwide. Time of death: Death always occurs during sleep at all times of night with a moderate increase in the early morning hours. Prematurity has a higher risk. The socio-economic standard of the family is usually low. Cigarette smoking and drug abuse by pregnant women increase the risk. The child is either quite well when put to bed, or may have only a minor upper respiratory tract infection (cold or snuffles), or minor gastrointestinal disturbance. Cot deaths are a major cause of death in infants in the first six months of life.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 38-week pregnant lady is traveling in a train. She gets an urge to pass stools. She goes into the washroom, but no sooner, she delivers a baby in the toilet room itself. Pick the wrong statement with respect to this scenario.", "options": [{"label": "A", "text": "This is called precipitate labor", "correct": false}, {"label": "B", "text": "This is extremely rare in multipara", "correct": true}, {"label": "C", "text": "If the birth occurs in the toilet bowl or into a bucket containing liquid, the Infant will inhale the liquid and blood, and meconium and vaginal mucus are found in the air-passages", "correct": false}, {"label": "D", "text": "Caput succedaneum and moulding of the head are absent", "correct": false}], "correct_answer": "B. This is extremely rare in multipara", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>This is extremely rare in multipara Precipitate labour is possible in multiparous with a large roomy pelvis but is extremely rare in primipara</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A PRECIPITATE LABOUR: Labour terminating in a very short time than that taken on the average, either in a primipara or multipara is called precipitate labour. All three stages of labour are merged into one. The Foetus is normal or premature. It is possible in multiparous with the large roomy pelvis but is extremely rare in primiparae. (Option B) It is highly improbable that any primiparous woman would be delivered during ordinary sleep without being aroused. Sometimes, a woman may not be able to distinguish the sense of fullness produced by the descent of a child from the feeling of bulky evacuation. The child may die from Suffocation by falling into a lavatory pan, Head injury and fracture of the skull with subdural haemorrhage often bilateral, by a fall on a hard floor, If the woman was standing, and Haemorrhage from the torn end of the cord. Option: C. If the birth occurs in the toilet bowl or into a bucket containing liquid, the infant will inhale the liquid and blood, and meconium and vaginal mucus are found in the air-passages. Microscopic examination of the lungs will show the foreign particles contained in the drowning fluid. In accidental falls, the hemorrhage is usually subdural and often bilateral. The length of the cord is 50 cm which does not allow the child to fall to the ground and is sufficiently strong to withstand the weight of the Fetus without breaking. The cord is torn most commonly at the foetal end than the placental end but is not torn in its middle or the placenta is expelled with the child. Option: D. Caput succedaneum and moulding of the head are absent. The fractures of the skull are usually fissured and limited to parietal bones but may extend to the frontal and the squamous part of temporal bones. Fractures due to forceps lie at points normally gripped by the instrument and are usually \"gutter\" or \"pond\" type</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A mother used to bring his child to the pediatric department almost every day with one complaint or another. The child was admitted several times. The pediatrician diagnosed it as a case of Munchausen’s syndrome of proxy. It is related with:", "options": [{"label": "A", "text": "Child abuse by father", "correct": false}, {"label": "B", "text": "Child abuse by mother", "correct": true}, {"label": "C", "text": "Child abuse by a third person", "correct": false}, {"label": "D", "text": "Not related to child abuse", "correct": false}], "correct_answer": "B. Child abuse by mother", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Child abuse by mother MUNCHAUSEN'S SYNDROME BY PROXY: This term is used to describe the actions of one person (usually a mother) who inflicts harm against another person (usually an infant or small child) in an attempt to gain sympathy and attention for both her own and the child's suffering. It is a variation that is a peculiar and dangerous type of child abuse usually involving the mother, in more than 90% of cases, in which children are brought to doctors for induced or fabricated signs and symptoms of illnesses with a fictitious history. More than 50% of mothers have personal abnormal illness behaviour in the form of factitious or somatoform disorder. Often the parental illness alternates with that of the child; the self-injurious behaviour of the parent may wax and wane as the factitious illness of the child waxes and wanes. Most mothers have a personality disorder. The child is admitted frequently to the hospital for medical evaluation for non-existent conditions.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Option:- Option: A, C & D: It is related to child abuse and more often by the mother than the father or any other person.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A child was found dead in his crib one morning. It was taken to the emergency and then for autopsy. It was labeled as Sudden Infant Death syndrome as no cause of death was found. The most commonly accepted hypothesis of Sudden Infant Death syndrome is:", "options": [{"label": "A", "text": "Viral infection of the respiratory tract", "correct": false}, {"label": "B", "text": "Allergic reaction to cow’s milk", "correct": false}, {"label": "C", "text": "Prolong sleep apnoea", "correct": true}, {"label": "D", "text": "Conduction system anomaly of the heart", "correct": false}], "correct_answer": "C. Prolong sleep apnoea", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Prolong sleep apnoea Acceptable hypothesis in the case of SIDS:- Some infants have prolonged ''sleep apnoea\" (a periodic failure to breathe during sleep), which makes them susceptible to hypoxia, which finally leads to bradycardia and cardiac arrest, but this has not been substantiated. Respiratory infection may produce a viraemia which adds to the sleep depression of the respiratory centres.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options :- Since prolonged sleep apnea is accepted as the most common cause, other Options are wrong even though some may be a comparatively rarer cause of SIDS.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "It is important to determine the age of the fetus recovered from the uterus during autopsy or autopsy on a fetus itself. Haase's rule estimates the age of Fetus from:", "options": [{"label": "A", "text": "Chest circumference", "correct": false}, {"label": "B", "text": "Head circumference", "correct": false}, {"label": "C", "text": "Crown heel length", "correct": true}, {"label": "D", "text": "Weight", "correct": false}], "correct_answer": "C. Crown heel length", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Crown heel length RULE OF HAASE: This is a rough method of calculating the age of the Foetus. The length of the Foetus is measured from the crown to the heel in centimeters. During the first five months of pregnancy the square root of the length gives the approximate age of the Fetus in months, e.g. a Foetus of 16 cm. is four months. Haase's Modification of Morison’s Law: During the last five months, the length in cm. divided by five gives the age in months, e.g., foetus of 35 cm. is 7 months.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B, & D. Chest circumference, Head circumference, and weight of the fetus has no significance in the Rule of Haase.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A child was brought to the emergency in an unconscious state. Shaking Baby syndrome is commonly associated with:", "options": [{"label": "A", "text": "Extradural haemorrhage", "correct": false}, {"label": "B", "text": "Subdural haemorrhage", "correct": true}, {"label": "C", "text": "Subarachnoid haemorrhage", "correct": false}, {"label": "D", "text": "Intracerebral haemorrhage", "correct": false}], "correct_answer": "B. Subdural haemorrhage", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Subdural haemorrhage Infantile whiplash syndrome: Shaking baby syndrome. Repeated shaking of unwanted/neglected child. Subdural hemorrhage, intraocular bleeding. X-ray findings: especially involving Ribs – ‘strings of beads’ – multiple rib fractures along the posterior angle of ribs Metaphyseal –epiphyseal injuries, Avulsion fractures of clavicle & acromion process</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Options: A, C & D. Extradural, subarachnoid or intracerebral haemorrhage is not seen in shaken baby syndrome.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Child abuse was found dead by his mother. The most commonly accepted hypothesis of Sudden Infant Death Syndrome is:", "options": [{"label": "A", "text": "Viral infection of the respiratory tract", "correct": false}, {"label": "B", "text": "Allergic reaction to cow’s milk", "correct": false}, {"label": "C", "text": "Prolonged sleep apnoea", "correct": true}, {"label": "D", "text": "Conduction system anomaly of the heart", "correct": false}], "correct_answer": "C. Prolonged sleep apnoea", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Prolonged sleep apnoea Important features:- Incidence- 0.2-0.4%. Age –2 wks to 2 yrs( majority occur between 6 weeks to 6 months) M: F-3: 2. Twins – increased risk among the members of the twin pair. Prematurity – increased risk. Most accepted hypothesis – is prolonged sleep apnoea. Other causes:–conduction system anomalies, hypersensitivity to cow’s milk, deficiency of parathyroid, selenium, Ca++, Mg++, and</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Other: A, B & D. All these factors do play a role in exacerbating brain hypoxia due to sleep apnoea but are not the most common cause of SIDS.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 20 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "The temperature of the body rises for the first 2 hours after death. The probable condition includes the following except:", "options": [{"label": "A", "text": "Septicemia", "correct": false}, {"label": "B", "text": "Tetanus", "correct": false}, {"label": "C", "text": "Strychnine poisoning", "correct": false}, {"label": "D", "text": "Frostbite", "correct": true}], "correct_answer": "D. Frostbite", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Frostbite Postmortem Caloricity: In this condition, the body's temperature remains raised for the first two hours after death. This occurs: When the regulation of heat production has been severely disturbed before death, as in sunstroke and in some nervous disorders, When there has been a significant increase in heat production in the muscles due to convulsions, as in tetanus and strychnine poisoning, etc., and When there has been excessive bacterial activity, as in septicemic conditions. cholera and other fevers.</p>\n<p><strong>Random:</strong></p><p>Explanation For incorrect Options:- Option: A, B & C . Septicaemia, Tetanus, and Strychnine poisoning are various causes of postmortem caloricity. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Entomology of the cadaver helps in establishing:", "options": [{"label": "A", "text": "Cause of death", "correct": false}, {"label": "B", "text": "Time since the death", "correct": true}, {"label": "C", "text": "Manner of death", "correct": false}, {"label": "D", "text": "Posture of the body at the time of death", "correct": false}], "correct_answer": "B. Time since the death", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Time since the death Time since death can be known by:- Cooling of the body. Postmortem lividity Rigor mortis Progress of decomposition, adipocere mummification Entomology of cadaver</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D . The cadaver's etymology doesn't help establish the cause of death, manner of death or posture of the body at the time of death. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "What is the time since death, based on the post-mortem finding shown in Image", "options": [{"label": "A", "text": "6 hours", "correct": false}, {"label": "B", "text": "12 hours", "correct": false}, {"label": "C", "text": "24 hours", "correct": false}, {"label": "D", "text": "36 hours", "correct": true}], "correct_answer": "D. 36 hours", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893488692-QTDF058003IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>36 hours The Marbling of Skin: The superficial veins, especially over the roots of the limb, thighs, sides of the abdomen, shoulders, chest and neck, are stained greenish-brown or purplish-red depending on the total amount of sulphhaemoglobin formation within the affected vessels (linear branching pattern) due to the haemolysis of red cells, which stains the wall of the vessel and infiltrates into the tissue, giving a marbled appearance (red, then the greenish pattern in skin resembling the branches of a tree) This starts in 24 hours but is prominent in 36 to 48 hours. The clotted blood becomes fluid, so the position of the postmortem staining is altered, and the fluid blood collects in the serous cavities. Putrefactive effusion of foul-smelling blood-stained fluid into the pleural cavities usually ~tarts at about the time when the skin becomes macerated. Such effusions usually do not exceed 60 to 100 ml. unless death results from drowning, when several hundred ml. of drowning medium, which oozed out through the lungs and visceral pleura, may be present in the thoracic cavities. The reddish-green colour of the skin may become dark green or almost black in 3 to 4 days.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C . Since the image shows skin marbling, it becomes prominent only in 36 hours. So, the other time frames in the options are earlier and are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The sign shown in the Illustration is indicative of", "options": [{"label": "A", "text": "Café coronary", "correct": false}, {"label": "B", "text": "Acute Alcohol intoxication", "correct": false}, {"label": "C", "text": "Death", "correct": true}, {"label": "D", "text": "Cocaine poisoning", "correct": false}], "correct_answer": "C. Death", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893488790-QTDF058005IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Death The opacity of the Cornea: This may occur in certain diseases (cholera, wasting diseases) before death. The opacity is due to drying and is delayed for about two hours if the lids are closed after death. If the eyelids are open for a few hours after death, a film of cell debris and mucus forms two yellow triangles on the sclera at each side of the iris, with the base towards the margin of the cornea and the apex towards the medial or lateral canthus of the eye, which become brown and then black called \"tache noir\" within 3 to 4 hours in the sclera, upon which dust settles, and the surface becomes wrinkled(artefact)</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & D . The Cornea's opacity has not been seen in café coronary, acute Alcohol intoxication or cocaine poisoning. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "After death, the body starts decomposing. Myiasis is a condition caused by fly maggots' infestation of the body. Flies (Musca domestica and M.vicinia) may deposit their eggs (pearly-white, one mm long; about 120 to 150 eggs at one sitting) on the fresh corpse in any natural or traumatically created shaded orifices. Studying these insects helps in determining the time since death. What is the study of the form and behaviour of insects termed?", "options": [{"label": "A", "text": "Entomology", "correct": true}, {"label": "B", "text": "Anthropology", "correct": false}, {"label": "C", "text": "Odontology", "correct": false}, {"label": "D", "text": "Thanatology", "correct": false}], "correct_answer": "A. Entomology", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Entomology Entomology- It studies insects and their offspring. Entomology helps in calculating the time since the death of a dead body by studying the type of insects present and their larvae stage.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Anthropology- Anthropology is the scientific study of human beings, especially of their origin, development, customs and beliefs. Forensic anthropology is the examination of human skeletal remains for law enforcement agencies to help recover human remains, determine the identity of unidentified human remains, interpret trauma, and estimate the time since death. Option: C. Odontology- The scientific study of the structure and diseases of teeth is known as odontology. Forensic dentistry or forensic odontology handles, examines and evaluates dental evidence in criminal justice cases. This is done using dental records, including radiographs, antemortem (before death), post-mortem (after death) photographs, and DNA. Option: D. Thanatology- Thanatology deals with death in all its aspects. It investigates the mechanisms and forensic aspects of death, such as bodily changes accompanying death and the postmortem period, as well as wider psychological and social aspects of</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Myiasis is a condition caused by fly maggots' infestation of the body. Flies (Musca domestica and M.vicinia) may deposit their eggs (pearly-white, one mm long; about 120 to 150 eggs at one sitting) on the fresh corpse in any natural or traumatically created shaded orifices. These include between the lips or the eyelids, in the nostrils, genitalia, or the margins of a fresh wound, ears, mouth, hair and the ground body interface, within a few minutes after death, and sometimes even before death during the agonal period. When skin decomposition begins, the eggs can be deposited anywhere. How long do the maggots or larvae hatch from these eggs deposited in the decomposing body during summertime?", "options": [{"label": "A", "text": "10 to 12 hours", "correct": false}, {"label": "B", "text": "8 to 24 hours", "correct": true}, {"label": "C", "text": "6 to 12 hours", "correct": false}, {"label": "D", "text": "4 to 24 hours", "correct": false}], "correct_answer": "B. 8 to 24 hours", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>8 to 24 hours In 8 to 24 hours in summer, larvae or maggots (white, segmented, 1 to 2 mm. in length at birth; 12 mm. when fully grown) are produced from the eggs, which crawl into the interior of the body and produce powerful proteolytic enzymes, and destroy the soft tissues. The maggots burrow under the skin and make tunnels and sinuses, which hasten putrefaction by allowing air and bacteria. The maggots become pupae (dark-brown, barrel-shaped, 6 mm. in length) in 3 to 6 days, and the pupae become adult flies in three to six days. Thus, the complete life cycle from maggots to adult flies takes 5 to 6 days in summer.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. 10 to 12 hours- WRONG option Option: C. 6 to 12 hours- WRONG option Option: D. 4 to 24 hours- WRONG option</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A driver wearing a seat belt suddenly applies brakes to avoid a collision. Which of the following body part is most likely to be injured?", "options": [{"label": "A", "text": "Spleen", "correct": false}, {"label": "B", "text": "Mesentery", "correct": true}, {"label": "C", "text": "Liver", "correct": false}, {"label": "D", "text": "Abdominal aorta", "correct": false}], "correct_answer": "B. Mesentery", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Mesentery Seat Belt Injuries: Seat belts are of the lap strap and diagonal shoulder type, which are of the \"inertial reel\" type, which allows slow movement but jams at a sudden tug. They are less effective than three-point Small intestine avulsions, intestinal, omental, and mesenteric lacerations, and intestinal contusion and perforations occur, known as \"seat belt syndrome,\" due to acute flexion over a lap strap. The spleen, liver, pancreas, caecum, and bladder rupture occurs due to compression between the belt and vertebrae. Abrasions, contusions, and hematomas of the lower abdomen and chest wall can directly result from seat belt trauma. The abdominal aorta can be crushed. Transverse lumbar vertebrae fractures, usually at the second or third segment of the interspace, can occur due to acute trunk hyperflexion over the belt fulcrum. The posterior arch, pedicle, or transverse processes may be fractured.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C, & D. Spleen, Liver, and aorta may be crushed in a seat belt injury, but they are not the most likely Injured part of the body. Hence there are better answers than these three options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A car driver was admitted with multiple small lacerations on his head. Sparrow foot marks are seen in:", "options": [{"label": "A", "text": "Gunshot injuries", "correct": false}, {"label": "B", "text": "Vitriolage", "correct": false}, {"label": "C", "text": "Stab injury of the face", "correct": false}, {"label": "D", "text": "Windshield glass injury", "correct": true}], "correct_answer": "D. Windshield glass injury", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Windshield glass injury Multiple, short linear, angular, rectangular, and square, punctate lacerations of the face are produced due to the shattering of the windscreen glass into multiple small rectangular, square, or cubical fragments with relatively blunt edges (\"sparrow foot\" marks; dicing injuries). They are relatively superficial. Thin pieces of windscreen glass may be embedded in the wounds or found loose in the clothing. There may be partial avulsion of the skin.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Gunshot injuries don't cause minor lacerations rather it causes deep wound. Option: B. Vitriolage is the throwing of acid on a person. It doesn't produce minor lacerations but rather more significant Option: C. Stab injury causes a deeper cut wound than minor Hence it is not the correct answer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A motorcycle rider was found dead at a roadside. He was riding fast without a helmet, and his motorcycle skidded. Motorcyclist fracture is:", "options": [{"label": "A", "text": "Ring fracture", "correct": false}, {"label": "B", "text": "Comminuted fracture", "correct": false}, {"label": "C", "text": "Skull divided into two halves", "correct": true}, {"label": "D", "text": "Subdural hemorrhage", "correct": false}], "correct_answer": "C. Skull divided into two halves", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Skull divided into two halves Hinge fracture - The skull's base is divided into two halves, each moving independently of the other like a hinge, the so-called motorcyclist's fracture. Hinge fractures are usually associated with brainstem injuries, particularly Ponto-medullar tears.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A. Ring or Foramen fractures: It is fissured fracture of the skull which encircles the head in such a manner that the anterior third is separated at its junction with the middle and posterior third The fracture line runs at about 3 – 5 cm. outside the foramen magnum at the back and sides of the skull and passes forwards through the middle ears and roof of the nose, so the head is separated from the spine. Option: B . Comminuted fractures: The bone is broken into multiple pieces in this skull fracture variety. e.g., RSA, fall from a height on a hard surface, and from blows by weapons with a large striking surface, kick by an animal, bullet injury, resembles a spider’s web or mosaic Option: D. Subdural Haemorrhage: It is common in childhood or old age. Occurs in subdural space between the dura mater and arachnoid due to rupture of bridging or communicating veins, inferior cerebral veins, and cortical veins,e., the source of blood is venous or capillary, not arterial. Found in alcoholics, old persons, and children. Death may occur if the bleeding is> 50 ml.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 13 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "An adolescent was brought for medical examination. He said that he was passive in a sodomy act. Lateral traction test is used to identify ___ in unnatural sexual offences:", "options": [{"label": "A", "text": "Habitual active agent", "correct": false}, {"label": "B", "text": "Habitual passive agent", "correct": true}, {"label": "C", "text": "Active in paedophile", "correct": false}, {"label": "D", "text": "Active in bestiality", "correct": false}], "correct_answer": "B. Habitual passive agent", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Habitual passive agent Lateral buttock traction test: A thumb is placed on each side of the anus, and lateral traction is applied. In persons who are not accustomed to sodomy, there will be reflex constriction of the anal sphincter. In a habitual passive agent of sodomy, complete relaxation of the sphincter occurs with dilation of the opening, which may be four to five cm in diameter, through which the rectum can be seen.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Since the lateral buttock traction test is used to identify chronic passive agents, other Options are not significant in this question. Hence there are better answers than these three options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Sexual perversion in which sexual gratification is obtained or increased by the suffering of pain?", "options": [{"label": "A", "text": "Eonism", "correct": false}, {"label": "B", "text": "Fetishism", "correct": false}, {"label": "C", "text": "Sadism", "correct": false}, {"label": "D", "text": "Masochism", "correct": true}], "correct_answer": "D. Masochism", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Masochism In masochism, sexual gratification is obtained or increased by the suffering of pain. Masochists get pleasure from being beaten, abused, and humiliated, enslaved, degraded or dominated by their sexual partner, and they tend to place themselves repeatedly in self-defeating situations.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: Eonism or Transvestism - A transvestite is a person whose whole personality is dominated by the desire to be identified and thought of as a member of the opposite sex. Option B: Fetichism - A fetish is a deviant stimulus or object of sexual desire. Fetichism means the use of such things for sexual gratification. In this, recurrent, intense sexual fantasies, sexual urges or behaviour involving the use of living or non-living objects occur. Option C: Sadism - In sadism, sexual gratification is obtained or increased from acts of physical cruelty or infliction of pain upon one's partner.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The sin of Gomorrah is also known as?", "options": [{"label": "A", "text": "Anal coitus", "correct": false}, {"label": "B", "text": "Oral coitus", "correct": true}, {"label": "C", "text": "Lesbianism", "correct": false}, {"label": "D", "text": "Bestiality", "correct": false}], "correct_answer": "B. Oral coitus", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Oral coitus Buccal coitus, also called Coitus per os or sin of Gomorrah). According to the Bible, this sin is common in Gomorrah, hence the name. In this sexual offence, the male organ is introduced in the mouth, another male or female but usually a child.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Since the sin of Gomorrah refers to oral coitus, other Options are not significant in this question. Hence these Options are different from the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Sexual asphyxia is associated with:", "options": [{"label": "A", "text": "Masochism", "correct": true}, {"label": "B", "text": "Sadism", "correct": false}, {"label": "C", "text": "Fetichism", "correct": false}, {"label": "D", "text": "Voyeurism", "correct": false}], "correct_answer": "A. Masochism", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Masochism Sexual asphyxia cases are associated with some form of abnormal sexual behaviour, usually masochism and transvestism.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Sadism - In sadism, sexual gratification is obtained or increased from acts of physical cruelty or infliction of pain upon one's partner. Option: C. Fetichism - A fetish is a deviant stimulus or object of sexual desire. Fetichism means the use of such things for sexual gratification. In this, recurrent, intense sexual fantasies, sexual urges or behaviour involving the use of living or non-living objects occur. Option: D. Voyeurism- It is the counterpart of exhibitionism. Voyeur (the so-called Peeping Tom) is defined as one who experiences recurrent, intense, sexually arousing fantasies, sexual urges or behaviours involving observing an unsuspecting person who is naked, in the process of disrobing, or engaged in sexual activity.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "An accused of sodomy was brought for examination. Lateral traction test is done in unnatural sexual offences in?", "options": [{"label": "A", "text": "Habitual active agent", "correct": false}, {"label": "B", "text": "Pedophilia active agent", "correct": false}, {"label": "C", "text": "Bestiality active agent", "correct": false}, {"label": "D", "text": "Habitual passive agent", "correct": true}], "correct_answer": "D. Habitual passive agent", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Habitual passive agent Lateral buttock traction test: A thumb is placed on each side of the anus, and lateral traction is applied in persons who are not accustomed to sodomy; there will be reflex constriction of the anal sphincter. In a habitual sodomite a complete relaxation of the sphincter occurs with dilation of the opening which may be four to five cm. in diameter, through which the rectum can be seen.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, B & C. Since the lateral buttock traction test is used to identify chronic passive agents, other Options are not significant in this question. Hence there are better answers than these three options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person “X” has excessive sexual desire and forces his wife into sexual intercourse now and then. He also gets sexual satisfaction by inducing his wife to have sexual intercourse with other men and watching the same. This is", "options": [{"label": "A", "text": "Troilism + satyriasis", "correct": true}, {"label": "B", "text": "Troilism + nymphomania", "correct": false}, {"label": "C", "text": "Fetichism + satyriasis", "correct": false}, {"label": "D", "text": "Fetichism + nymphomania", "correct": false}], "correct_answer": "A. Troilism + satyriasis", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Troilism + satyriasis TROILISM: It is a sexual practice involving three persons, 1 of one sex and one of the opposite It is an extreme degree of voyeurism. A perverted husband gets sexual satisfaction by inducing his wife into sexual intercourse with another man and watching the same Satyriasis:- excessive sexual desire in men.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B, C, D. Nymphomania: Excessive sexual desire in woman FETICHISM: --> A fetish is a deviant stimulus or object of sexual desire. Fetichism means the use of such things for sexual gratification. --> In this, recurrent, intense sexual fantasies, sexual urges, or behaviour involving living or non-living objects occur. --> In this, the person experiences sexual excitement leading to orgasm from part of a woman's body or some article belonging to her that has typically no sexual influence on the mind, e.g., underclothing. brassiere, dress, stocking, shoes, etc., which substitute for the female love object. The fetish may be only incidentally associated with the human body, g........ a flower. In some cases, a picture of the fetish object provides the sufficient stimulus. Sometimes, stealing the articles provides adequate sexual satisfaction, though often the fetish article is stored to the satisfaction of the fetish, or touching it gives him sex pleasure, or he may masturbate into the object. It is almost exclusively seen in males. It is harmless, but rarely it may drive the person to obtain his fetish object through violence, or other criminal act, e.g., things may be stolen, or women may be attacked either as part of robbery with violence or because the fetish provides the trigger for rape or indecent assault.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A die-hard fan of a bollywood actress somehow managed to get the actress’s personal mobile number and started calling her repeatedly. She responded and acknowledged for supporting her during the first call, but since he kept on calling her on alternate days she asked him to not do so on and blocked him..1 week later he started contacting her through another mobile number of his for which she filed a complaint in police station. Under which IPC section will the case be lodged against him?", "options": [{"label": "A", "text": "354 A", "correct": false}, {"label": "B", "text": "354 B", "correct": false}, {"label": "C", "text": "354 C", "correct": false}, {"label": "D", "text": "354 D", "correct": true}], "correct_answer": "D. 354 D", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>354 D S. 354D, I.P.C: Stalking: Whoever follows a woman and contacts or attempts to contact such woman w foster personal interaction repeatedly, despite a clear indication of disinterest by such woman, or monitors the use by a woman of the internet, a e-mail or any other form of electronic communication, (imprisonment up to 3 years and fine).</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A: 354A- Assault or use of criminal force to a woman with intent to outrage her modesty. Option B: 354B- Assault or use of criminal force to a woman or compelling her to be naked with intent to disrobe. Option C: 354C- Related to Voyeurism.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Unnatural sexual acts are punishable under section ………IPC:", "options": [{"label": "A", "text": "375", "correct": false}, {"label": "B", "text": "376", "correct": false}, {"label": "C", "text": "377", "correct": true}, {"label": "D", "text": "498", "correct": false}], "correct_answer": "C. 377", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>377 Voluntary sexual intercourse against the order of nature with any man, or woman, or animal is an unnatural sex offence (S. 377, I.P.C.). Penetration is sufficient to constitute the offence. These offences are punishable with imprisonment for life or up to ten years and also with a fine.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A - 375 IPC - gives a definition of rape. Option B - 376 IPC - gives the punishment for rape according to its severity. Option D - 498 IPC - Enticing or taking away or detaining a married woman with criminal intention is punishable with imprisonment up to 2 years.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The type of sexual perversion where gratification is obtained by wearing clothes of the opposite sex:", "options": [{"label": "A", "text": "Tribadism", "correct": false}, {"label": "B", "text": "Voyeurism", "correct": false}, {"label": "C", "text": "Transvestitism", "correct": true}, {"label": "D", "text": "Satyriasis", "correct": false}], "correct_answer": "C. Transvestitism", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Transvestitism TRANSVESTISM OR EONISM: The term is derived from the name of Chevelier d' Eon Beamont, a Frenchman, who preached this. A transvestite (trans = opposite; vesta = clothing) is a person whose whole personality is dominated by the desire to be identified and thought of as a member of the opposite sex.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Tribadism- Female homosexuality is known as tribadism or lesbianism. Option: B. Voyeurism- experiencing recurrent, intense, sexually arousing fantasies, sexual urges or behaviours involving the act of observing an unsuspecting person who is naked, in the process of disrobing, or engaged in sexual activity. Option: D. Satyriasis:- excessive sexual desire in men.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which of the sexual perversion is punishable?", "options": [{"label": "A", "text": "Masochism", "correct": false}, {"label": "B", "text": "Eonism", "correct": false}, {"label": "C", "text": "Nymphomaniac", "correct": false}, {"label": "D", "text": "Exhibitionism", "correct": true}], "correct_answer": "D. Exhibitionism", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Exhibitionism An exhibitionist is one who, over six months or more, experiences recurrent, intense, sexually amusing fantasies, sexual urges or behaviour, including the exposure of one's genitals to an unsuspecting stranger. It usually occurs before adulthood. It is done mainly by males, often by children or persons of the opposite sex. The pervert adopts a childish method of attracting attention to himself to experience sexual gratification at the time of the exhibition, without physical contact. In some cases, the act is premeditated. Occasionally, women may expose themselves in public. Majority of them are psychopathic or suffer from compulsive neurosis and suffer from alcoholism, epilepsy, senile dementia, GPI, etc. TT is an obscene act punishable under S. 294, I.P.C. with imprisonment up to three months or a fine.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Sexual gratification while inflicting Injury by the other partner refers to masochism Option: B. Transvestism/Eonism- Wearing clothes of the opposite sex refers to Transvestism. Option: C. Nymphomaniac: Excessive sexual desires in a woman.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Camera trial is a court proceeding used to examine:", "options": [{"label": "A", "text": "Rape accused", "correct": false}, {"label": "B", "text": "Rape victim", "correct": true}, {"label": "C", "text": "Catamite", "correct": false}, {"label": "D", "text": "Pedophile", "correct": false}], "correct_answer": "B. Rape victim", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Rape victim New anti-rape law: THE CRIMINAL LAW (AMENDMENT) ACT, 2013 A man is said to commit rape if he Penetrates his penis, to any extent, into the vagina, mouth, urethra or anus of a woman or makes her do so with him or any other person; or Insert to any extent any object or a part of the body not being the penis into the vagina or urethra or anus of a woman Makes her do so with him or any other person; or Manipulates any part of the body of a woman to cause penetration into the vagina, urethra, anus or any part of the body of such woman makes her do so with him or any other person Applies his mouth to the vagina, anus, urethra of a woman or makes her do so with him or any other person Under circumstances falling under any of the seven following descriptions: - 1 – against her will. 2 – without her consent. 3 – with her consent when consent has been obtained by putting her or any person in whom she is interested in fear of death or hurt. 4– with her consent, when the man knows that he is not her husband and that her consent is given because she believes that he is another man she is or believes herself to be lawfully married. 5 – with her consent, when, at the time of giving consent, because of unsoundness of mind or intoxication or the administration of by him personally or through another of any stupefying or unwholesome substance she is unable to understand the nature and consequences of that to which she gives consent. 6– with or without her consent, when she is under sixteen. 7 -– when she is unable to communicate consent. Exception: A medical procedure or intervention shall not constitute rape. Sexual intercourse by a man with his wife, not being under 15 years of age, is not rape. Consent – a woman 18 yrs & above can give valid consent for sexual intercourse. What constitutes rape – slightest penetration Statutory rape – sexual intercourse with a girl below 18 years, not being the wife. Disclosure of Identity of victim: Camera trial 228A IPC –who prints or publishes without authorization by proper authority the name or any material which will result in identifying the rape victim. Punishes any person with imprisonment up to 2 years.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C , & D. Rape accused, catamite, and Pedophile doesn't require a camera trial. Hence these three options are not the correct answers.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Greek Love is:-", "options": [{"label": "A", "text": "Buccal coitus", "correct": false}, {"label": "B", "text": "Tribadism", "correct": false}, {"label": "C", "text": "Sadism", "correct": false}, {"label": "D", "text": "Sodomy", "correct": true}], "correct_answer": "D. Sodomy", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Sodomy Unnatural sexual offenses (377 IPC) Sodomy or anal coitus. Buccal or oral coitus. Bestiality Lesbianism or tribadism or Sapphism. Sodomy– Also called buggery- Greek Love</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Buccal coitus: Oral coitus – Sin of Gomorrah. Fellatio – involving male organs. Cunnilingus – involving female organs. Option: B. Lesbianism: Tribadism /Sapphism, Practiced in Isle of Lesbos (Greece), Ruled by Queen Sappho Active lesbian – butch // dyke, passive lesbian – femme Option: C. Sadism: the tendency to derive pleasure, especially sexual gratification, from inflicting pain, suffering, or humiliation on others.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 22 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A person was found in an uncontrollable spasm after ingestion some vegetables. His wife showed the doctor the seeds. Identify the seeds shown in the below Image.", "options": [{"label": "A", "text": "Calotropis", "correct": false}, {"label": "B", "text": "Nux vomica", "correct": true}, {"label": "C", "text": "Ricinus communis", "correct": false}, {"label": "D", "text": "Semecarpus anacardium", "correct": false}], "correct_answer": "B. Nux vomica", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682894060539-QTDF078001IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Nux vomica The seeds of nux vomica are flat, circular discs or slightly convex on one side, concave on the other, two-and-half cm in diameter, and 6 mm. in thickness. They are ash-grey or light-brown in color, have a shiny surface, and are covered with radiating silky fibers. They are tough, challenging, and difficult to pulverize. The bark, wood, and leaves contain brucine but no strychnine. Strychnine is used as a respiratory stimulant, rodenticide, and for killing stray dogs.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "The seeds in the Image have a close resemblance to", "options": [{"label": "A", "text": "Dhatura seeds", "correct": false}, {"label": "B", "text": "Abrus precatorius seeds", "correct": false}, {"label": "C", "text": "Castor seeds", "correct": true}, {"label": "D", "text": "Kuchila seeds", "correct": false}], "correct_answer": "C. Castor seeds", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682894060754-QTDF078002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Castor seeds This is the seed of the castor plant. The castor plant (arandi) grows all over India. Fruit is 1.2 to 2.5 cm. long, three-lobed, softly spiny, blue-green, or rose-red when immature, brown, and bristly when ripe and dry. Seeds are variable, smooth, flattened-oval, mottled, light and dark brown, white with yellow-brown or gray markings, or black or red. They are of two—sizes, big and small. The tiny seeds are about .2 cm. long and 0.8 cm. broad and resemble croton seeds. The seeds resemble those of Croton</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A farmer was admitted in an unconscious state from his farm where he was spraying insecticide. All of the following are features of organophosphate poisoning except:", "options": [{"label": "A", "text": "Tachycardia", "correct": true}, {"label": "B", "text": "Clinical picture stimulating asthma", "correct": false}, {"label": "C", "text": "Miosis", "correct": false}, {"label": "D", "text": "Diarrhoea", "correct": false}], "correct_answer": "A. Tachycardia", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Tachycardia A muscarine-like effect that potentiates postganglionic parasympathetic activity and affects pupils, bronchial mucosa, salivary and sweat glands (stimulated), urinary bladder (contracted), cardiac sinus node (blocked'· Muscarinic receptors for acetylcholine are found primarily in the smooth muscles, heart, and exocrine glands. Nicotine-like stimulation is followed by paralysis of postganglionic and somatic motor nerves, causing twitching of the eyelids, tongue, and facial muscles, followed by neuromuscular block and paralysis. Nicotinic signs and symptoms result from the accumulation of acetylcholine at the endings of motor nerves to skeletal muscles and autonomic ganglia. Central nervous system stimulation followed by depression causes headaches, giddiness, restlessness, apprehension, tremors, ataxia, insomnia, coma, and death.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A patient who was admitted with poisoning has positive Chovstek’s sign. Chovstek’s sign is seen in which poisoning?", "options": [{"label": "A", "text": "Oxalic acid", "correct": true}, {"label": "B", "text": "Strychnine", "correct": false}, {"label": "C", "text": "Hydrocyanic acid", "correct": false}, {"label": "D", "text": "Arsenic", "correct": false}], "correct_answer": "A. Oxalic acid", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Oxalic acid Those who survive for a few hours after oxalic acid poisoning develop hypocalcemia, because it readily combines with the calcium ion in the body tissues and causes its withdrawal from them, showing Chvostek’s sign. Death usually occurs within 12 hours.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A lady was complaining of abdominal pain and constipation. On endoscopy, phytobezoar was diagnosed. Phytobezoar is:", "options": [{"label": "A", "text": "Intake of indigestible plant materials", "correct": true}, {"label": "B", "text": "Vegetable balls", "correct": false}, {"label": "C", "text": "Hairball", "correct": false}, {"label": "D", "text": "Drugs ball", "correct": false}], "correct_answer": "A. Intake of indigestible plant materials", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Intake of indigestible plant materials Abezoar is an indigestible mass of material found in the gastrointestinal tract, such as hair, food, seeds, or another ingested substance. A phytobezoar, the most common type of bezoar, is composed of indigestible fruit and vegetable fibers, such as cellulose, hemicellulose, lignin, or tannins. Most phytobezoars occur in patients with impaired gastric motility or digestion, usually following gastric surgery (such as a Billroth I or II gastrectomy) or as a consequence of poor motility in patients with diabetic gastroparesis, mixed connective tissue disease, or hypothyroidism. Impaired gastric peristalsis, low gastric acidity, and loss of normal pyloric function can contribute to phytobezoar formation. Patients with phytobezoars may experience epigastric pain or discomfort, nausea, vomiting, early satiety, weight loss, diarrhea, dysphagia, or upper gastrointestinal ulcerations and hemorrhage</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person accidentally ate some mushrooms and was having an unpleasant hallucination. Which of the following drug may be useful in treating a case of mushroom poisoning?", "options": [{"label": "A", "text": "Physostigmine", "correct": false}, {"label": "B", "text": "Nitrites", "correct": false}, {"label": "C", "text": "Atropine", "correct": true}, {"label": "D", "text": "None of the above", "correct": false}], "correct_answer": "C. Atropine", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Atropine Treatment of mushroom poisoning: Stomach wash with potassium permanganate. Activated charcoal. Forced diuresis. Benzylpenicillin 3 lakhs to one million units daily. Atropine sulfate. Antiphalloidien serum. Thioctic acid is obsolete. Haemodialysis Symptomatic.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted with poisoning. The consultant asked the attendant resident to be ready with an atropine injection. Atropine is used for the following EXCEPT:", "options": [{"label": "A", "text": "Organophosphorous poisoning", "correct": false}, {"label": "B", "text": "Mushroom poisoning", "correct": false}, {"label": "C", "text": "Physostigmine overdose", "correct": false}, {"label": "D", "text": "Glaucoma", "correct": true}], "correct_answer": "D. Glaucoma", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Glaucoma Atropine is contraindicated in Glaucoma.</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option: A, B & C. Atropine is indicated for treating Organophosphorus poisoning, Mushroom poisoning & Physostigmine overdose.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 17 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "Several persons were brought to the emergency with simple, non-fatal and fatal injuries. Railway spine refers to one of the following types of injury to the spinal cord:", "options": [{"label": "A", "text": "Contusion", "correct": false}, {"label": "B", "text": "Laceration", "correct": false}, {"label": "C", "text": "Concussion", "correct": true}, {"label": "D", "text": "Transaction", "correct": false}], "correct_answer": "C. Concussion", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Concussion Concussion of the spinal cord – Occurs in railway & motor car collisions & is known as ‘railway spine’. Also occurs due to dislocation/ fracture of vertebrae, damage by effusion of blood, and bullet injury, all causing severe direct injury to the spinal cord.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option A, B & D Contusion, laceration and transaction do not cause railway spine. Contusion, laceration and transaction do not cause railway spine.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A middle aged person is travelling in a car. The vehicle comes to a sudden halt. The mechanism of injury shown below", "options": [{"label": "A", "text": "Hyperflexion+ extension", "correct": false}, {"label": "B", "text": "Hyper extension + hyperflexion", "correct": true}, {"label": "C", "text": "Hyperextension + flexion", "correct": false}, {"label": "D", "text": "Flexion +y hyper extension", "correct": false}], "correct_answer": "B. Hyper extension + hyperflexion", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682893044544-QTDF047002IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hyper extension + hyperflexion Whiplash injury: It is caused due to a violent acceleration or deceleration force applied to the passenger, usually the front seat occupant. When the vehicle comes to a sudden stop due to head-on obstruction, the heavy head continues to move forward (acute hyperflexion). When the body comes to rest, or the head strikes an obstruction in front, there is then a reactionary hyperextension as the head is thrown backwards, this double movement being known as the 'whiplash'. lf a vehicle is hit violently from behind by another car, the head is thrown violently back into hyperextension and then forwards after the body stops moving. In either case. This violent extension-flexion movement can cause atlantooccipital dislocation in one-third of patients, or less commonly, a fracture-dislocation in the lower part of the spine at about C 5 and 6. Laceration of tendons and joint capsules, intra-articular haemorrhages and tears with separation of the cartilaginous lining of articular surfaces may occur. Fatal contusion or laceration of the spinal cord may occur without fracture of the Fracture or dislocation can also occur in the upper dorsal spine, often around T5 to T10. Head restraints (headrests) prevent hyperextension of the neck to a certain degree.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A, C & D. Anything other than the combination of hyperextension and hyperflexion is not related to whiplash injury. Hence there are better answers than these three options.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A person was admitted with multiple injuries over the body. The attending resident was making MLC; however, he could not interpret some of the injuries accurately. The lacerated wound looks like an incised wound at:", "options": [{"label": "A", "text": "Scrotum", "correct": false}, {"label": "B", "text": "Thigh", "correct": false}, {"label": "C", "text": "Bone with thin overlying tissue", "correct": true}, {"label": "D", "text": "Abdomen", "correct": false}], "correct_answer": "C. Bone with thin overlying tissue", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Bone with thin overlying tissue Incised–looking lacerated wounds: Blunt force on areas where the skin is close to the bone and the subcutaneous tissues are scanty may produce a wound which, by the linear splitting of the tissue, may look like an incised wound.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. On the scrotum with loose skin, incised wounds look like lacerated wounds. Option: B & D. Injuries over the thigh and abdomen do not create such misinterpretation.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Police personnel brought a person found dead on the side of a road with multiple fractures over the head, chest and lower limbs. Ante mortem fractures differ from postmortem fractures by:", "options": [{"label": "A", "text": "Effusion of blood", "correct": true}, {"label": "B", "text": "Comminuted type", "correct": false}, {"label": "C", "text": "No sign of injury over the skin", "correct": false}, {"label": "D", "text": "Lack of oedema", "correct": false}], "correct_answer": "A. Effusion of blood", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Effusion of blood Feature Description Antemortem Perimortem Postmortem Signs of plastic response Permanent deformation of the bone after exceeding the elastic response limit Presence or absence depending on the fracture location and nature Present Absent Bone flakes Small bone fragments attached to the impact site NA Present Absent Edge morphology The relative sharpness of the fracture margin Smooth Sharp, incomplete or bend-edges Squared edges at right angles to the bone surface-no bending Fracture angle The angle between the cortical table and the direction of the fracture NA Acute or obtuse Right Fracture texture or tactile roughness Morphology of the broken bone surface Smooth Smooth Rough Preponderant outline NA Regular Irregular Cortical delamination or beveling The cleavage between the diploe and the inner/outer table NA Present Absent Cranial bone remodelling Bony bridges between the fragments Present Absent Absent</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 14 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A pregnant woman is examined by the doctor at seven weeks of pregnancy. One hand is placed on her abdomen, and the other hand is in the vagina to look for consistency in the cervix. This is", "options": [{"label": "A", "text": "Hegar’s sign", "correct": true}, {"label": "B", "text": "Braxton hicks sign", "correct": false}, {"label": "C", "text": "Goodell’s sign", "correct": false}, {"label": "D", "text": "Piskacek’s sign", "correct": false}], "correct_answer": "A. Hegar’s sign", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hegar’s sign Hegar's sign is positive at about the sixth week. If one hand is placed on the abdomen and two fingers of another hand in the vagina, the firm hard cervix is felt and above it, the elastic body of the uterus, while between the two, the isthmus is felt as a soft compressible area. This is the most valuable physical sign of early pregnancy</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option: B. Braxton-Hick's sign : Intermittent, painless uterine contractions are difficult to be observed before the third month but are easily felt after the fourth month. Each contraction lasts about a minute and lasts for about two to three minutes. They are present even when the Foetus is dead. Option: C. From the second month, the cervix progressively softens from below upward, which is well-marked by the fourth month. This is known as Goodell's sign. There is a shortening of the cervix towards the last months of pregnancy. The orifice becomes circular instead of being transverse and admits the point of the finger to a greater depth. Option: D. Piskacek's sign notes a noticeable lateral bulge or soft prominence at one of the locations where the uterine tube meets the uterus.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A couple with a marital life of 25 years have always wanted to have a child. However, due to unexplained reasons, they couldn't have one. However, at the age of 50, the lady starts to experience morning sickness, breast changes, an increase in the size of the abdomen and fetal movements. The couple is feeling delighted visits an obstetrician. The doctor does a UPT and also a scan of the abdomen. The tests showed negative results. This is", "options": [{"label": "A", "text": "Pseudocyesis", "correct": false}, {"label": "B", "text": "Spurious pregnancy", "correct": false}, {"label": "C", "text": "Phantom pregnancy", "correct": false}, {"label": "D", "text": "All of the above", "correct": true}], "correct_answer": "D. All of the above", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>All of the above Option: A, B, C, D Pseudocyesis /spurious pregnancy/ phantom pregnancy): It is usually observed in patients nearing menopause or in younger women who intensely desire children. Most women suffer from some form of psychic or hormonal disorder. Such patients may present all the subjective symptoms of pregnancy associated with a considerable increase in the size of the abdomen which may be due to abnormal deposition of fat or to Tympanites or occasionally due to ascites. Changes in breasts are sometimes present; in many cases, the woman may imagine fetal In some cases, pregnancy had gone to \"full term,\" and frank labor pains occurred, which ceased abruptly when the patients were told they were not pregnant. Clinical examination (if necessary under anesthesia) and X-ray examination will solve the problem. A woman can be pregnant and not know it. In rare cases, pregnancy may progress to full term without the woman being aware.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "During ward rounds, the consultant asks the intern, “She is G1P1, and delivered a baby boy by Normal full term vaginal delivery six days back. What can you say about her lochia?” The intern is expected to say:", "options": [{"label": "A", "text": "Lochia is bright red and contains clots called lochia rubra", "correct": false}, {"label": "B", "text": "Lochia is yellowish grey called lochia alba", "correct": false}, {"label": "C", "text": "Lochia is paler and serous called lochia serosa", "correct": true}, {"label": "D", "text": "Either b or c", "correct": false}], "correct_answer": "C. Lochia is paler and serous called lochia serosa", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Lochia is paler and serous called lochia serosa Lochia, after five days, appears pale and serous, called the lochia serosa. Option: A, B, C, D: The Lochia is a discharge from the uterus that lasts two or three weeks. It has a peculiar sour, disagreeable odor. The discharge is bright red during the first 4 to 5 days and contains large clots (lochia rubra). During the next four days, it becomes severe and paler in color (lochia serosa). After the ninth-day color becomes yellowish-grey or turbid (lochia alba) until its final disappearance.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A couple came to an IVF clinic for a child as the husband was azoospermic. The attending doctor suggested an artificial insemination donor. Which of the following statement is incorrect regarding artificial insemination donors?", "options": [{"label": "A", "text": "Consent of both wife and husband is required", "correct": false}, {"label": "B", "text": "Written consent from the donor’s wife is required", "correct": false}, {"label": "C", "text": "The recipient cannot select donor", "correct": false}, {"label": "D", "text": "Child born out of such an act is legitimate.", "correct": true}], "correct_answer": "D. Child born out of such an act is legitimate.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Child born out of such an act is legitimate. Specific recommendations have been made when a donor is used. They are : The consent of the donor and his wife is essential. The identity of the donor must remain secret. The donor should not know to whom the semen is donated and the result of insemination. The donor must be mentally and physically healthy and not suffer from any hereditary or familial disease. The donor must not be a spouse's relative; he should have had his own children. The race and characteristics of the donor should resemble those of the woman's husband as closely as possible. The donor should be of the same blood group as the husband. There should not be any Rh incompatibility between the donor and recipient. The physician should be permitted to use his best judgment to select the donor. The couple should be psychologically fit and emotionally stable. The woman to be inseminated and her husband must consent in writing that an unknown should be used. A witness must be present when insemination is done. It is usually wise to use \"pooled\" semen. When the husband's semen is mixed with that of a donor, there is the technical possibility that the husband may be the child's father. The physician who administers artificial insemination should avoid delivering the child. This will prevent the necessity of either falsifying the birth records or disclosing the true paternity in those records. Usually, a single donor's semen is not used to produce more than ten children.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Post-delivery, the uterus of a female is mid-way between the umbilicus and pubis, one finger admission in the cervix, and serous discharge from the vagina. The time since delivery is:", "options": [{"label": "A", "text": "Less than five days", "correct": false}, {"label": "B", "text": "About one week", "correct": true}, {"label": "C", "text": "24hrs", "correct": false}, {"label": "D", "text": "More than ten days", "correct": false}], "correct_answer": "B. About one week", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>About one week The Uterus after delivery : Immediately after delivery, the contracted and retracted body of the uterus feels like a hard muscular tumor, the upper border of which lies about three cm. below the umbilicus. It then diminishes in size by about one-and-half cm. a day. On the sixth day, it is midway between the umbilicus and pubis; by the 12th day 5 cm. above the pelvic brim; by the 14th day at the level of the pubes and returns to normal condition in nine weeks. The uterus becomes normal in weight in 6 to 8 weeks. The Cervix after delivery: It is soft and dilated, and its edges tom and lacerated transversely. The internal os begins to close in the first 24 hours. The external os is smooth and patent and admits two fingers. At the end of a week, one finger is detected with difficulty and closed in two weeks. The Lochia : It is a uterine discharge that lasts for two or three weeks. It has a peculiar sour, disagreeable odor. The discharge is bright red during the first 4 to 5 days and contains large clots (lochia rubra). During the next four days, it becomes severe and paler in color (lochia serosa). After the ninth-day color becomes yellowish-grey or turbid (lochia alba) until its final disappearance.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A couple was married for two years. Because of various misunderstandings, the husband applied for divorce. It was a mutual decision. In the court proceedings, she pretended to be pregnant and delivered a baby girl, too, just to obtain more property and money as her share. The child is called", "options": [{"label": "A", "text": "Suppositious child", "correct": false}, {"label": "B", "text": "Fictitious child", "correct": false}, {"label": "C", "text": "Posthumous child", "correct": false}, {"label": "D", "text": "Both A and B", "correct": true}], "correct_answer": "D. Both A and B", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Both A and B Option: A, B, D: Supposititious Children : It means fictitious children. A woman may pretend pregnancy and delivery and later produce a living child as her own, or she may substitute a male child for a female child born of her or for an abortion. This is done to obtain money or to claim the Other legal issues involved are blackmailing a man or bringing a charge of breech of promise of marriage against a man. In such cases, the woman should be examined for signs of pregnancy and delivery. The medical evidence is valid only when the age of the supposititious child does not correspond to the date of the pretended delivery. DNA fingerprinting will be conclusive Option: C. Posthumous Child : It is a child born after the death of its father, the mother being conceived by the said father. Legal issues involved are legitimacy, inheritance of property, and compensation case for slander against the mother.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A sperm bank was looking for a sperm donor for a couple. In artificial insemination, the donor should have all except:-", "options": [{"label": "A", "text": "Age less than 40 years", "correct": false}, {"label": "B", "text": "Free of STDs", "correct": false}, {"label": "C", "text": "Married should have at least two healthy children", "correct": false}, {"label": "D", "text": "Blood relation with the recipient", "correct": true}], "correct_answer": "D. Blood relation with the recipient", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Blood relation with the recipient Certain recommendations have been made when a donor is used. They are: Consent of the donor and his wife is essential. The identity of the donor must remain secret. The donor should not know to whom the semen is donated and the result of insemination. The donor must be mentally and physically healthy and not suffer from any hereditary or familial disease. The donor must not be a relative of either spouse, he should have had children of his own. The race and characteristics of the donor should resemble those of the woman's husband as closely as possible. The donor should be of the same blood group as that of the husband. There should not be any Rh incompatibility between the donor and recipient. The physician should be permitted to use his best judgment to select the donor. The couple should be psychologically fit and emotionally stable. The woman to be inseminated and her husband must consent in writing that an unknown donor should be used. A witness must be present when insemination is done. It is usually wise to use \"pooled\" semen. When the husband's semen is mixed with that of a donor, there is the technical possibility that the husband may be the child's father. The physician who administers artificial insemination should avoid delivering the child. This will avoid the necessity of either falsifying the birth records or disclosing the true paternity in those records. Usually, a single donor's semen is not used to produce more than ten children.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Choose the correct statement about the Image given below", "options": [{"label": "A", "text": "This is a tiny opening with a large posterior component called micro perforate opening", "correct": true}, {"label": "B", "text": "This is an imperforate type of hymen", "correct": false}, {"label": "C", "text": "This is a cribriform type of hymen with a tiny opening", "correct": false}, {"label": "D", "text": "This is a septate type of opening.", "correct": false}], "correct_answer": "A. This is a tiny opening with a large posterior component called micro perforate opening", "question_images": ["https://dbmi-data.s3.ap-south-1.amazonaws.com/photos-1682894093031-QTDF079008IMG1.JPG"], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>This is a tiny opening with a large posterior component called micro perforate opening Micro perforate: Tiny opening with a large posterior component</p>\n<p><strong>Random:</strong></p><p>Explanation for incorrect options: - Option: B, C, D. Types of hymen Semilunar or crescentic (commonest type): the opening is placed anteriorly. Notches or clefts are seen at 10 and 11 o clock positions, which may be equal in size or more prominent on one side. Annular: the opening is oval and situated near the center of the membrane. Infantile: a small linear opening in the middle. Cribriform: several openings. Vertical: the opening is vertical. Septate: two lateral openings occur side by side, separated partially or completely by a thin strip of tissue. Micro perforate Tiny opening with a large posterior component. Fimbriated, Imperforate: no opening.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 18 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">
Instructions
Test Features:
Multiple choice questions with single correct answers
Timer-based testing for realistic exam conditions
Mark questions for review functionality
Comprehensive results and performance analysis
Mobile-optimized interface for learning on-the-go
Start Test
<!-- Quiz Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="quiz"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <!-- Progress Bar --> <div class="w-full bg-gray-200 rounded-full h-3 mb-4"> <div class="progress-bar h-3 rounded-full" id="progress-bar" style="width: 0%"></div> </div> <!-- Question Header --> <div class="flex flex-col md:flex-row justify-between items-center mb-4"> <h2 class="text-lg font-semibold" id="question-number">Question <span>1</span> of 4</h2> <p class="text-lg font-semibold mt-2 md:mt-0" id="timer">Time Remaining: <span>00:00</span></p> </div> <!-- Question Content --> <div class="mb-6" id="question-content"> <p class="text-gray-800 mb-4" id="question-text"></p> <div class="flex flex-wrap gap-4 mb-4" id="question-images"></div> <div class="space-y-3" id="options"></div> </div> <!-- Navigation Buttons --> <div class="flex flex-col md:flex-row justify-between items-center gap-2 md:gap-4"> <div class="flex gap-2 w-full md:w-auto"> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="previous-btn">Previous</button> <button class="bg-[#2c5281] text-white px-4 py-3 w-full md:w-32 h-14 rounded-lg hover:bg-[#2c5281] transition" id="next-btn">Next</button> </div> <div class="flex items-center gap-2"> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="mark-review"> Review <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> <path d="M10 2a1 1 0 00-1 1v14l3.293-3.293a1 1 0 011.414 0L17 17V3a1 1 0 00-1-1H10z" /> </svg> </button> <button class="bg-transparent text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-100 transition flex items-center gap-1" id="nav-toggle"> Question 🧭 </button> <button class="bg-green-500 text-white px-6 py-3 w-44 h-14 rounded-lg hover:bg-green-600 transition w-full md:w-auto" id="submit-test">Submit Test</button> </div> </div> </section> <!-- Results Section --> <section class="container mx-auto px-4 md:px-6 pt-4 md:pt-6 pb-1 hidden section-transition" id="results"> <div class="bg-white rounded-lg shadow-md p-4 md:p-6"> <h2 class="text-2xl font-semibold mb-4">Anaesthesia Machine - Results</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <p><strong>Correct:</strong> <span id="correct-count" class="text-[#000000]">0</span></p> <p><strong>Wrong:</strong> <span id="wrong-count" class="text-[#000000]">0</span></p> <p><strong>Unanswered:</strong> <span id="unanswered-count" class="text-[#000000]-500">0</span></p> <p><strong>Marked for Review:</strong> <span id="marked-count" class="text-[#000000]">0</span></p> </div> <h3 class="text-lg font-semibold mb-4" id="result-question-number">Question <span>1</span> of 4</h3> <div class="space-y-6" id="results-content"></div> <div class="result-nav"> <button aria-label="Previous question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" disabled="" id="prev-result">Previous</button> <button aria-label="Toggle results navigation panel" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="results-nav-toggle">Result 🧭</button> <button aria-label="Next question result" class="result-nav-btn bg-[#2c5281] text-white px-6 py-2 rounded-lg hover:bg-[#2c5281] transition" id="next-result">Next</button> </div> <div class="mt-6 flex space-x-4 button-group md:flex-row flex-col"> <button class="bg-green-500 text-white px-6 py-2 rounded-lg hover:bg-green-600 transition" id="take-again">Take Again</button> </div> </div> </section> <!-- Exit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="exit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Leave Test?</h2> <p class="text-gray-700 mb-4">Your progress will be lost if you leave this page. Are you sure you want to exit?</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="continue-test">No, Continue</button> <button class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition" id="exit-test">Yes, Exit</button> </div> </div> </div> <!-- Submit Confirmation Modal --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 hidden" id="submit-modal" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white rounded-lg p-6 max-w-sm w-full"> <h2 class="text-xl font-semibold mb-4">Confirm Submission</h2> <p class="text-gray-700 mb-2">You have attempted <span id="attempted-count">0</span> of 4 questions.</p> <p class="text-gray-700 mb-4"><span id="unattempted-count">0</span> questions are unattempted.</p> <div class="flex justify-end space-x-4"> <button class="bg-gray-300 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-400 transition" id="cancel-submit">Cancel</button> <button class="text-white px-4 py-2 rounded-lg hover:bg-[#1a365d] transition" style="background-color: #2c5281;" id="confirm-submit">Submit Test</button> </div> </div> </div> <!-- Quiz Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 nav-panel hidden overflow-y-auto" id="nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Questions Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-nav">Close</button> </div> </div> <!-- Results Navigation Panel --> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-start justify-center p-4 z-50 results-nav-panel hidden overflow-y-auto" id="results-nav-panel" style="align-items: flex-start; padding-top: 33vh;"> <div class="bg-white shadow-lg p-4 rounded-lg w-full max-w-2xl max-h-[80vh] overflow-y-auto"> <h2 class="text-lg font-semibold mb-4">Results Navigation</h2> <div class="mb-4"> <select class="w-full p-2 border rounded-lg text-gray-700" id="results-nav-filter"> <option value="all">All Questions</option> <option value="answered">Answered</option> <option value="unanswered">Unanswered</option> <option value="marked">Marked for Review</option> </select> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> </div> <div class="grid grid-cols-5 gap-2 md:gap-3" id="results-nav-grid"></div> <button class="mt-4 bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition w-full" id="close-results-nav">Close</button> </div> <!-- JavaScript Logic --> <script> // Enable debug mode for detailed logging const DEBUG_MODE = true; // Log debug messages function debugLog(message) { if (DEBUG_MODE) { console.log(`[DEBUG] ${message}`); } } // Initialize questions with error handling let questions = []; let currentResultQuestion = 0; // State for current question in results try { debugLog("Attempting to parse questions_json"); questions = [{"text": "A gives evidence in the witness box stating that B had informed him that he had seen C committing a crime. This is", "options": [{"label": "A", "text": "Direct evidence", "correct": false}, {"label": "B", "text": "Indirect evidence", "correct": false}, {"label": "C", "text": "Circumstantial evidence", "correct": false}, {"label": "D", "text": "Hearsay evidence", "correct": true}], "correct_answer": "D. Hearsay evidence", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Hearsay evidence Hearsay Evidence: It is any statement made by any person about what he did not personally witness, or evidence he obtained from a third party, which is presented in the Court in order to assert that the facts contained in the statement are true, e.g., A gives evidence in the witness box stating that B had informed him that he had seen C committing a crime. In such case, direct evidence can be given only by B that he had seen C committing a crime</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Direct Evidence: Evidence of a fact that is actually in issue, e.g., an electric blanket that has caused injury, prescription, or a consent form. Option: B & C. Indirect or Circumstantial Evidence: It is not the direct testimony of an eye witness, but has a bearing upon the fact of the other and subsidiary facts which are relied upon as consistent (S.6, l.E.A.), e.g., in case of the alleged murder of A by B at a certain place on a particular day and time, the circumstantial evidence would be that C saw B with a knife on that day at that place, a few minutes before the murder. Circumstantial evidence requires the Court to draw logical or reasonable inferences from the information presented.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A has seen B and C, fighting with sticks on a certain road on a particular day and time. So A becomes", "options": [{"label": "A", "text": "Common witness", "correct": true}, {"label": "B", "text": "Expert witness", "correct": false}, {"label": "C", "text": "Both A and B", "correct": false}, {"label": "D", "text": "Hostile witness", "correct": false}], "correct_answer": "A. Common witness", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Common witness Types: Witnesses are of two types : Common Expert</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. A common witness (witness of fact; occurrence witness) is a person who gives evidence about the facts observed or perceived by him. He must show that he was capable of perceiving the fact by one of his own senses and that he actually observed this fact. This principle is commonly known as the \"first-hand knowledge rule\", which may be used to establish the exact circumstances of the case for the Court, e.g., A has seen B and C, fighting with sticks on a certain road on a particular day and time. In the case of a traffic accident, the person who witnessed the accident becomes a common witness. Option: B. An expert witness is a person who has been trained or is skilled or has knowledge, experience or education in a technical or scientific subject, and capable of drawing opinions and conclusions from the facts observed by himself or noticed by others, e.g., a doctor, firearms expert, fingerprints expert, handwriting expert, etc. (S. 45, I.E.A.) Option: D. Hostile Witness- Hostile witness is one who is supposed to have some interest or motive for concealing part of the truth, or for giving completely false evidence. The Court will declare a witness as hostile on the suggestion of the lawyer of the party who has summoned the witness or prosecution lawyer.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "Which is not true about dying deposition?", "options": [{"label": "A", "text": "Recorded only by the Magistrate.", "correct": false}, {"label": "B", "text": "Oath is taken.", "correct": false}, {"label": "C", "text": "Not practised in India.", "correct": false}, {"label": "D", "text": "Cross-examination is not permitted.", "correct": true}], "correct_answer": "D. Cross-examination is not permitted.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Cross-examination is not permitted. Cross-examination is not permitted in the Dying declaration which is followed in India.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- DYING DEPOSITION: Option: A & B. It is a statement of a person on oath, recorded by the Magistrate in the presence of the accused or his lawyer, who is allowed to cross-examine the witness. Option: C. This procedure is not followed in India.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A 27year old male who witnessed a murder was summoned by a higher court to give testimony about the crime. He had earlier given his statement after taking the oath in the lower court and it was recorded. But this time he deliberately gave false evidence about the crime in the higher court under the oath. The prosecutor's lawyer proved that the man is having personal benefits now from this case and so is giving false evidence. The judge noted this and sentenced the man to punishment, which of the following is a correct statement regarding this crime?", "options": [{"label": "A", "text": "It is known as Perjury which is punishable for 7 years under the Sec. 191IPC.", "correct": false}, {"label": "B", "text": "Causing willful disappearance of evidence is punishable under Sec. 193IPC.", "correct": false}, {"label": "C", "text": "In case of a hostile witness, leading questions are allowed during the chief examination.", "correct": true}, {"label": "D", "text": "This wilful giving of false evidence is defined as Perjury under Sec. 197IPC.", "correct": false}], "correct_answer": "C. In case of a hostile witness, leading questions are allowed during the chief examination.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>In case of a hostile witness, leading questions are allowed during the chief examination. This given case is known as Perjury, where the witness under the oath gives false/ fabricated evidence. A hostile witness is one who is supposed to have some interest or motive for concealing part of the truth, or for giving completely false evidence. The court will declare a witness hostile on the suggestion of the lawyer of the party who has summoned the witness or prosecution lawyer. On declaration of a witness as hostile, he can be cross-examined by the same side lawyer. Perjury means giving wilful false/ fabricated evidence. Whoever, being legally bound by an oath, or by an express provision of law to state the truth, or being bound by law to make a declaration upon any subject, makes any statement which is false, and which he either knows or believes to be false or does not believe to be true, is said to give false evidence. It occurs if the person's earlier statement regarding the facts on oath and subsequent statement on oath are opposed to each other, and cannot be reconciled. The witness is liable to be prosecuted for perjury, and the imprisonment may extend to seven years (S. 193I.P.C.). A leading question is one which suggests to the witness the answer desired, or which includes a material fact, and admits of a conclusive answer by a simple “Yes” or “No”. Leading questions are allowed only during cross-examination. They are defined under 141IEA. Leading questions are not permitted in the chief examination. For hostile witnesses, leading questions can be asked by the defence lawyer during the chief examination. The judge can ask questions at any time during the Leading questions are defined under 141IEA. Leading questions are not permitted in the chief examination but are permitted in cross-examination. For hostile witnesses, leading questions can be asked by the defence lawyer during the chief examination.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. Witness is liable to be prosecuted for perjury, and the imprisonment may extend to seven years (S. 193I.P.C.), where the witness under the oath gives false/ fabricated evidence. Option: B. Causing willful disappearance of evidence is punishable under Sec. 201PC. Option: D. Perjury means giving wilful false/ fabricated evidence. Whoever, being legally bound by an oath, or by an express provision of law to state the truth, or being bound by law to make a declaration upon any subject, makes any statement which is false, and which he either knows or believes to be false or does not believe to be true, is said to give false evidence. It is defined under Sec. 191IPC.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "You were summoned as an Expert witness to testify regarding a homicide case by the High Court. You went with your related documents as you were the doctor who performed the autopsy and was asked to take an oath and was questioned by the public prosecutor as well as by the defence lawyer. Which of the following given options regarding the examination of witnesses in the Court are correctly matched? Direct examination - 1st examination of witness; questioned by the lawyer for the side which has summoned him. Leading question is allowed in the chief examination. Cross-examination - in a murder trial, the defence witness is cross-examined by the public prosecutor. Re-direct examination - it is conducted by the opposite side lawyer which has not called the witness. As an expert witness the doctor must memorise all the facts, as the law doesn't allow you to refresh your memory from reports already submitted in the court. There is no time limit for cross-examination. Select the correct answer from the given below code:", "options": [{"label": "A", "text": "1,3,6", "correct": true}, {"label": "B", "text": "2,4,5", "correct": false}, {"label": "C", "text": "1,4,5", "correct": false}, {"label": "D", "text": "2,3,6", "correct": false}], "correct_answer": "A. 1,3,6", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>1,3,6 An expert witness is a person who has been trained or is skilled or has knowledge, experience or education in a technical or scientific subject, and capable of drawing opinions and conclusions from the facts observed by himself or noticed by others; eg.- Doctor, firearm expert, fingerprint expert. The evidence of the witness is recorded as follows Sec 138 to 159IEA. Under the Indian Oath Act, of The witness has to take an oath in the witness box before he gives his evidence. He should take the oath as follows: \"I do swear in the name of God, that what I shall state shall be the truth, the whole truth, and nothing but the truth\". If the witness is an atheist, he has to \"solemnly affirm\" instead of \"swearing in the name of God.\" An oath is a declaration required by the law, which is compulsory and holds the witness responsible for the consequences of his evidence. A child below 12 years is not required to take an oath. Examination-in-chief (direct examination) (Sec.137I.E.A.) - This is the first examination of a witness. It consists of questions put to him by the lawyer (counsel or advocate) for the side which has summoned him. In criminal acts committed by an individual or group, the State becomes a party instead of the aggrieved person and starts criminal prosecution, which is titled \"State versus A\".(Point 1) ln, a criminal trial, the burden to prove is always on the prosecution (adversarial system of trial). and the accused is presumed to be innocent till the contrary is proved against him. In Government prosecution cases. the public prosecutor first examines the witness. If a witness is called by a private party, he is first examined by the lawyer of that party. The object is to elicit all relevant, convincing medical facts and the conclusions that the doctor has drawn from the facts. The doctor may have to interpret the findings of non-medical ancillary investigations provided by scientific laboratories, analysts and serologists, in all cases where the medical aspects are at issue. Before giving evidence, it is advisable that the doctor meets the public prosecutor, and discuss the previously prepared report, the certificate of death, photographs, etc., that the witness intends to show in the Court, and an outline or pattern should be worked out for the best way to elicit his testimony. A leading question is one which suggests to the witness the answer desired, or which includes a material fact, and admits of a conclusive answer by a simple \"Yes\" or \"No\". \"Was this injury caused by a sharp weapon?\" Was the length of the cut 3 cm?\" They are all leading questions, as they suggest the answer \"Yes\" or \"No\". The proper questions should be: \"What type of weapon would cause this injury?\" What was the length of the cut?. Where was it seen\"?(Point 2) Cross-examination - In this, the witness is questioned by the lawyer for the opposite party, i.e., a lawyer for the accused (defence lawyer). In a murder trial, the defence witness is cross-examined by the public prosecutor. The main objects are To elicit facts favourable to his case, To test the accuracy of the statements made by the witness, To modify, or explain what has been said, To develop new or old facts, (5) to discredit the witness, and To remove any undue or excessive emphasis which may have been given to any of them. There is no time limit for cross-examination. Leading questions are allowed in cross-examination. (Points 3 and 6) Re-examination (Re-direct examination): This is conducted by the lawyer for the side which has called the witness. The object is to correct any mistake or to clarify or add details to the statements the witness has made in cross-examination. It is an opportunity for the witness to explain more fully some answer which might appear damaging to his direct evidence, because of skilful questioning or tactics by the cross-examiner. The witness should not bring in any new matter at this stage. The opposing lawyer has the right of re-cross-examination on the new point raised. Leading questions are not allowed. (Point 4) Never attempt to memorise reports presented in court. The law allows refreshing your memory from copies of reports already submitted or from case notes and similar records made at the time of examination. (Point 5) Options regarding Direct examination, cross-examination and the time limit for cross-examination are correctly matched to the given explanations.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: B. Facts about the leading question, Re-direct examination and about refreshing memory from reports in the court are wrongly matched. Option: C. Re-examination is conducted by the lawyer for the side which has called the witness and the law allows you to refresh your memory from copies of reports already submitted or from case notes and similar records made at the time of examination, it is wrongly matched. Option: D. Leading questions are allowed only during cross-examination. They are defined under 141IEA. Leading questions are not permitted in the chief examination. For hostile witnesses, leading questions can be asked by the defence lawyer during the chief examination.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}, {"text": "A murder case was reported by the Police of a locality. The servant was held as the main accused and was arrested by the police. But the servant kept on repeating that he did not commit the crime and was innocent. The police and Forensic experts collected various evidences from the crime site and a dagger was found stained with blood with fingerprints over it. The Court summoned You for the hearing as you are a fingerprint expert to give your testimony. Which of the following is a correct statement regarding a common witness and an expert witness?", "options": [{"label": "A", "text": "An expert witness cannot claim for conduct money.", "correct": false}, {"label": "B", "text": "Person especially skilled in foreign law, science or art (Sec.45IEA) is an Expert witness.", "correct": true}, {"label": "C", "text": "A common witness can volunteer a statement in between the proceedings in the court.", "correct": false}, {"label": "D", "text": "Leading questions cannot be asked to a hostile witness during the chief examination.", "correct": false}], "correct_answer": "B. Person especially skilled in foreign law, science or art (Sec.45IEA) is an Expert witness.", "question_images": [], "explanation_images": [], "explanation": "<p><strong>Solution:</strong></p><p>Person especially skilled in foreign law, science or art (Sec.45IEA) is an Expert witness. A witness is a person who gives sworn testimony(evidence) in a court of law as regards facts and/or inferences that can be drawn from these. There are 2 types of witnesses most commonly - Common witness; Expert witness. Common witness/ ordinary or lay witness- someone who observes and gives evidence about the crime which he saw as he was present there at the time of it. Eg. an eyewitness. Expert witness or skilled witness- opinion obtained from a qualified person. Eg. doctor, firearm expert, fingerprint expert, serologist. An expert witness can give his expert opinion from his area of expertise or qualification. Expert witness is a person who has been trained or skilled in a technical or scientific subject. He can volunteer a statement if he feels that justice is likely to be miscarried owing of the court having failed to elicit an important point. Doctors are not necessarily expert witnesses. Medical practitioners are considered ‘professional witnesses’ akin to witnesses of fact when he/she is providing factual medical evidence. They can be testifying about events that they themselves have observed, e.g., the doctor may confirm the physical examination findings in case of an accident or a diagnosis made after investigation or may report the findings of an X-ray or treatment given to the patient. The difference between a ‘professional witness’ and an ‘expert witness’ is that experts can offer opinions beyond the facts of what they have personally witnessed and can respond to questions about hypothetical situations posed to them. Hostile witness is a person who willfully or with motive (bribe/intimidation) conceals part of the truth or tells a lie or gives completely false evidence in a court. It is contradictory to the statement the witness made in the previous deposition (e.g. statement recorded by the police). Any of the above two witnesses can be declared hostile witnesses. S.No. Feature Common witness Expert witness 1. Definition Gives evidence about the facts observed or perceived by him (Sec. 118 IEA) Person especially skilled in foreign law, science or art (Sec. 45 IEA) 2. Volunteering a statement Not allowed Can volunteer 3. Drawing an inference from observations Not allowed Can draw 4. Expressing an opinion on observations made by others Not allowed Can express 5. Responsibility Less Highly Responsible 6. Punishment for giving false evidence Less punishment Severely punished in some countries 7. Conduct money Cannot claim Can claim 8. Examples Any person Handwriting or fingerprint expert, doctor, chemical examiner A leading question is one which suggests to the witness the answer desired, or which includes a material fact and admits of a conclusive answer by a simple \"Yes\" or \"No\". Leading questions are allowed only during cross-examination. They are defined under 141IEA. Leading questions are not permitted in the chief examination. For hostile witnesses, leading questions can be asked by the defence lawyer during the chief examination. Expert witness or skilled witness- opinion obtained from a qualified person. Eg. doctor, firearm expert, fingerprint expert, serologist.</p>\n<p><strong>Random:</strong></p><p>Explanation For Incorrect Options:- Option: A. An expert witness can claim for conduct money. Conduct money is the fee offered or paid to a witness in civil cases, at the time of serving the summons to meet the expenses for attending the Court. In criminal cases, conveyance charges and daily allowance can be claimed by the expert witness according to Government rules. Option: C. A common witness cannot volunteer a statement in between the proceedings in the court, only an expert witness can volunteer statements. Option: D. Leading questions are allowed only during cross-examination. They are defined under 141IEA. Leading questions are not permitted in the chief examination. For hostile witnesses, leading questions can be asked by the defence lawyer during the chief examination.</p>\n<p>@dams_new_robot</p>", "bot": "@dams_new_robot", "video": ""}]; if (!Array.isArray(questions) || questions.length === 0) { throw new Error("Questions data is empty or invalid"); } debugLog(`Successfully parsed ${questions.length} questions`); } catch (e) { console.error("Failed to parse questions_json:", e); document.getElementById('error-message').innerHTML = "Error loading quiz data. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; // Fallback to sample questions for testing questions = [ { text: "What is 2 + 2?", options: [ { label: "A", text: "3", correct: false }, { label: "B", text: "4", correct: true }, { label: "C", text: "5", correct: false }, { label: "D", text: "6", correct: false } ], correct_answer: "B. 4", question_images: [], explanation_images: [], explanation: "<p>2 + 2 = 4</p><p>@dams_new_robot</p>", bot: "@dams_new_robot", audio: "", video: "" } ]; debugLog("Loaded fallback questions"); } // Quiz state let currentQuestion = 0; let answers = new Array(questions.length).fill(null); let markedForReview = new Array(questions.length).fill(false); let timeRemaining = 16 * 60; // Duration in seconds let timerInterval = null; const quizId = `{title.replace(/\s+/g, '_').toLowerCase()}`; // Unique ID for local storage // Load saved progress function loadProgress() { try { debugLog("Loading progress from localStorage"); const saved = localStorage.getItem(`quiz_${quizId}`); if (saved) { const { savedAnswers, savedMarked, savedTime } = JSON.parse(saved); answers = savedAnswers || answers; markedForReview = savedMarked || markedForReview; timeRemaining = savedTime !== undefined ? savedTime : timeRemaining; debugLog("Progress loaded successfully"); } else { debugLog("No saved progress found"); } } catch (e) { console.error("Error loading progress:", e); debugLog("Failed to load progress: " + e.message); } } // Save progress function saveProgress() { try { debugLog("Saving progress to localStorage"); localStorage.setItem(`quiz_${quizId}`, JSON.stringify({ savedAnswers: answers, savedMarked: markedForReview, savedTime: timeRemaining })); debugLog("Progress saved successfully"); } catch (e) { console.error("Error saving progress:", e); debugLog("Failed to save progress: " + e.message); } } // Initialize quiz function initQuiz() { try { debugLog("Initializing quiz"); loadProgress(); const startButton = document.getElementById('start-test'); if (!startButton) { throw new Error("Start test button not found"); } startButton.addEventListener('click', startQuiz); debugLog("Start test button listener attached"); document.getElementById('previous-btn').addEventListener('click', showPreviousQuestion); document.getElementById('next-btn').addEventListener('click', showNextQuestion); document.getElementById('mark-review').addEventListener('click', toggleMarkForReview); document.getElementById('nav-toggle').addEventListener('click', toggleNavPanel); document.getElementById('submit-test').addEventListener('click', showSubmitModal); document.getElementById('continue-test').addEventListener('click', closeExitModal); document.getElementById('exit-test').addEventListener('click', () => { debugLog("Exiting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('cancel-submit').addEventListener('click', closeSubmitModal); document.getElementById('confirm-submit').addEventListener('click', submitTest); document.getElementById('take-again').addEventListener('click', () => { debugLog("Restarting test"); localStorage.removeItem(`quiz_${quizId}`); window.location.reload(); }); document.getElementById('close-nav').addEventListener('click', toggleNavPanel); document.getElementById('nav-filter').addEventListener('change', updateNavPanel); document.getElementById('prev-result').addEventListener('click', showPreviousResult); document.getElementById('next-result').addEventListener('click', showNextResult); document.getElementById('results-nav-toggle').addEventListener('click', toggleResultsNavPanel); document.getElementById('close-results-nav').addEventListener('click', toggleResultsNavPanel); document.getElementById('results-nav-filter').addEventListener('change', updateResultsNavPanel); debugLog("Quiz initialized successfully"); } catch (e) { console.error("Failed to initialize quiz:", e); debugLog("Failed to initialize quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('start-test').disabled = true; } } // Start quiz function startQuiz() { try { debugLog("Starting quiz"); document.getElementById('instructions').classList.add('hidden'); document.getElementById('quiz').classList.remove('hidden'); showQuestion(currentQuestion); startTimer(); updateNavPanel(); debugLog("Quiz started successfully"); } catch (e) { console.error("Error starting quiz:", e); debugLog("Failed to start quiz: " + e.message); document.getElementById('error-message').innerHTML = "Error starting quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); document.getElementById('quiz').classList.add('hidden'); document.getElementById('instructions').classList.remove('hidden'); } } // Show question function showQuestion(index) { try { debugLog(`Showing question ${index + 1}`); currentQuestion = index; const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } document.getElementById('question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('question-text').innerHTML = q.text || "No question text available"; const imagesDiv = document.getElementById('question-images'); imagesDiv.innerHTML = q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg">`).join('') : ''; const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = q.options && q.options.length > 0 ? q.options.map(opt => ` <button class="option-btn w-full text-left p-3 border rounded-lg ${answers[index] === opt.label ? 'selected' : ''}" onclick="selectOption(${index}, '${opt.label}')" aria-label="Option ${opt.label}: ${opt.text}"> ${opt.label}. ${opt.text} </button> `).join('') : '<p class="text-red-500">No options available</p>'; document.getElementById('previous-btn').disabled = index === 0; document.getElementById('next-btn').disabled = index === questions.length - 1; document.getElementById('mark-review').classList.toggle('marked', markedForReview[index]); updateProgressBar(); saveProgress(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying question:", e); debugLog("Failed to display question: " + e.message); } } // Select option function selectOption(index, label) { try { debugLog(`Selecting option ${label} for question ${index + 1}`); answers[index] = label; const optionsDiv = document.getElementById('options'); const optionButtons = optionsDiv.querySelectorAll('.option-btn'); optionButtons.forEach(btn => { const btnLabel = btn.textContent.trim().split('.')[0]; btn.classList.toggle('selected', btnLabel === label); }); updateNavPanel(); saveProgress(); debugLog(`Option ${label} selected for question ${index + 1}`); } catch (e) { console.error("Error selecting option:", e); debugLog("Failed to select option: " + e.message); } } // Toggle mark for review function toggleMarkForReview() { try { debugLog(`Toggling mark for review on question ${currentQuestion + 1}`); markedForReview[currentQuestion] = !markedForReview[currentQuestion]; document.getElementById('mark-review').classList.toggle('marked', markedForReview[currentQuestion]); updateNavPanel(); saveProgress(); debugLog(`Mark for review toggled for question ${currentQuestion + 1}`); } catch (e) { console.error("Error marking for review:", e); debugLog("Failed to mark for review: " + e.message); } } // Navigate to previous question function showPreviousQuestion() { try { debugLog(`Navigating to previous question from ${currentQuestion + 1}`); if (currentQuestion > 0) { currentQuestion--; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to previous question:", e); debugLog("Failed to navigate to previous question: " + e.message); } } // Navigate to next question function showNextQuestion() { try { debugLog(`Navigating to next question from ${currentQuestion + 1}`); if (currentQuestion < questions.length - 1) { currentQuestion++; showQuestion(currentQuestion); } } catch (e) { console.error("Error navigating to next question:", e); debugLog("Failed to navigate to next question: " + e.message); } } // Handle question navigation click function handleQuestionNavClick(index) { try { debugLog(`Navigating to question ${index + 1} via nav panel`); showQuestion(index); toggleNavPanel(); } catch (e) { console.error("Error handling navigation click:", e); debugLog("Failed to navigate via nav panel: " + e.message); } } // Start timer function startTimer() { try { debugLog("Starting timer"); timerInterval = setInterval(() => { if (timeRemaining <= 0) { debugLog("Timer expired, submitting test"); clearInterval(timerInterval); submitTest(); } else { timeRemaining--; const minutes = Math.floor(timeRemaining / 60); const seconds = timeRemaining % 60; document.getElementById('timer').innerHTML = `Time Remaining: <span>${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}</span>`; saveProgress(); } }, 1000); debugLog("Timer started successfully"); } catch (e) { console.error("Error starting timer:", e); debugLog("Failed to start timer: " + e.message); } } // Update progress bar function updateProgressBar() { try { debugLog("Updating progress bar"); const progress = ((currentQuestion + 1) / questions.length) * 100; document.getElementById('progress-bar').style.width = `${progress}%`; debugLog("Progress bar updated"); } catch (e) { console.error("Error updating progress bar:", e); debugLog("Failed to update progress bar: " + e.message); } } // Update quiz navigation panel function updateNavPanel() { try { debugLog("Updating quiz navigation panel"); const filter = document.getElementById('nav-filter').value; const navGrid = document.getElementById('nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="question-nav-btn ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleQuestionNavClick(${i})" aria-label="Go to Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Quiz navigation panel updated"); } catch (e) { console.error("Error updating quiz navigation panel:", e); debugLog("Failed to update quiz navigation panel: " + e.message); } } // Update results navigation panel function updateResultsNavPanel() { try { debugLog("Updating results navigation panel"); const filter = document.getElementById('results-nav-filter').value; const navGrid = document.getElementById('results-nav-grid'); navGrid.innerHTML = questions.map((_, i) => { if (filter === 'answered' && !answers[i]) return ''; if (filter === 'unanswered' && answers[i]) return ''; if (filter === 'marked' && !markedForReview[i]) return ''; return ` <button class="result-nav-btn-grid ${answers[i] ? 'answered' : 'unanswered'} ${markedForReview[i] ? 'marked-nav' : ''}" onclick="handleResultNavClick(${i})" aria-label="Go to Result for Question ${i + 1}"> ${i + 1} </button> `; }).join(''); debugLog("Results navigation panel updated"); } catch (e) { console.error("Error updating results navigation panel:", e); debugLog("Failed to update results navigation panel: " + e.message); } } // Toggle quiz navigation panel function toggleNavPanel() { try { debugLog("Toggling quiz navigation panel"); const navPanel = document.getElementById('nav-panel'); navPanel.classList.toggle('hidden'); debugLog("Quiz navigation panel toggled"); } catch (e) { console.error("Error toggling quiz navigation panel:", e); debugLog("Failed to toggle quiz navigation panel: " + e.message); } } // Toggle results navigation panel function toggleResultsNavPanel() { try { debugLog("Toggling results navigation panel"); const resultsNavPanel = document.getElementById('results-nav-panel'); resultsNavPanel.classList.toggle('hidden'); if (!resultsNavPanel.classList.contains('hidden')) { updateResultsNavPanel(); } debugLog("Results navigation panel toggled"); } catch (e) { console.error("Error toggling results navigation panel:", e); debugLog("Failed to toggle results navigation panel: " + e.message); } } // Handle result navigation click function handleResultNavClick(index) { try { debugLog(`Navigating to result for question ${index + 1} via nav panel`); showResults(index); toggleResultsNavPanel(); } catch (e) { console.error("Error handling result navigation click:", e); debugLog("Failed to navigate to result: " + e.message); } } // Show submit modal function showSubmitModal() { try { debugLog("Showing submit modal"); const attempted = answers.filter(a => a !== null).length; document.getElementById('attempted-count').textContent = attempted; document.getElementById('unattempted-count').textContent = questions.length - attempted; document.getElementById('submit-modal').classList.remove('hidden'); debugLog("Submit modal displayed"); } catch (e) { console.error("Error showing submit modal:", e); debugLog("Failed to show submit modal: " + e.message); } } // Close submit modal function closeSubmitModal() { try { debugLog("Closing submit modal"); document.getElementById('submit-modal').classList.add('hidden'); debugLog("Submit modal closed"); } catch (e) { console.error("Error closing submit modal:", e); debugLog("Failed to close submit modal: " + e.message); } } // Close exit modal function closeExitModal() { try { debugLog("Closing exit modal"); document.getElementById('exit-modal').classList.add('hidden'); debugLog("Exit modal closed"); } catch (e) { console.error("Error closing exit modal:", e); debugLog("Failed to close exit modal: " + e.message); } } // Submit test function submitTest() { try { debugLog("Submitting test"); clearInterval(timerInterval); document.getElementById('quiz').classList.add('hidden'); document.getElementById('submit-modal').classList.add('hidden'); document.getElementById('results').classList.remove('hidden'); showResults(0); // Start with first question // Trigger confetti animation confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); localStorage.removeItem(`quiz_${quizId}`); debugLog("Test submitted successfully"); } catch (e) { console.error("Error submitting test:", e); debugLog("Failed to submit test: " + e.message); } } function showResults(index) { try { debugLog(`Showing result for question ${index + 1}`); currentResultQuestion = index; let correct = 0, wrong = 0, unanswered = 0, marked = 0; answers.forEach((answer, i) => { const isCorrect = answer && questions[i].options.find(opt => opt.label === answer)?.correct; if (answer === null) unanswered++; else if (isCorrect) correct++; else wrong++; if (markedForReview[i]) marked++; }); const q = questions[index]; if (!q) { throw new Error(`Question ${index} is undefined`); } const userAnswer = answers[index]; const isCorrect = userAnswer && q.options.find(opt => opt.label === userAnswer)?.correct; const resultsContent = document.getElementById('results-content'); // Create scrollable container for explanation content resultsContent.innerHTML = ` <div class="border-4 ${isCorrect ? 'border-green-600 bg-green-100' : userAnswer ? 'border-red-600 bg-red-100' : 'border-gray-400 bg-gray-50'} p-4 rounded-lg overflow-hidden"> <p class="font-semibold">Question ${index + 1}: ${q.text || 'No question text'}</p> ${q.question_images && q.question_images.length > 0 ? q.question_images.map(url => `<img src="${url}" alt="Question Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} <p><strong>Your Answer:</strong> ${userAnswer ? `${userAnswer}. ${q.options.find(opt => opt.label === userAnswer)?.text || 'Invalid option'}` : 'Unanswered'}</p> <p><strong>Correct Answer:</strong> ${q.correct_answer || 'Unknown'}</p> <!-- Scrollable container for explanation --> <div class="mt-2 overflow-x-auto"> ${q.explanation || 'No explanation available'} </div> ${q.explanation_images && q.explanation_images.length > 0 ? q.explanation_images.map(url => `<img src="${url}" alt="Explanation Image" class="max-w-full h-auto rounded-lg my-2">`).join('') : ''} ${q.video ? ` <button class="play-video bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadVideo(this, '${q.video}', 'video-${index}')" aria-label="Play explanation video for Question ${index + 1}"> Play Video Explanation </button> <div id="video-${index}" class="video-container mt-2"></div> ` : '<p class="text-gray-500 mt-2">No video available</p>'} ${q.audio ? ` <button class="play-audio bg-[#2c5281] text-white px-4 py-2 rounded-lg mt-2" onclick="loadAudio(this, '${q.audio}', 'audio-${index}')" aria-label="Play audio explanation for Question ${index + 1}"> Play Audio Explanation </button> <div id="audio-${index}" class="audio-container mt-2"></div> ` : ''} </div> `; document.getElementById('correct-count').textContent = correct; document.getElementById('wrong-count').textContent = wrong; document.getElementById('unanswered-count').textContent = unanswered; document.getElementById('marked-count').textContent = marked; document.getElementById('result-question-number').innerHTML = `Question <span>${index + 1}</span> of ${questions.length}`; document.getElementById('prev-result').disabled = index === 0; document.getElementById('next-result').disabled = index === questions.length - 1; updateResultsNavPanel(); window.scrollTo({ top: 0, behavior: 'smooth' }); debugLog(`Result for question ${index + 1} displayed successfully`); } catch (e) { console.error("Error displaying result:", e); debugLog("Failed to display result: " + e.message); } } // Navigate to previous result function showPreviousResult() { try { debugLog(`Navigating to previous result from question ${currentResultQuestion + 1}`); if (currentResultQuestion > 0) { showResults(currentResultQuestion - 1); } } catch (e) { console.error("Error navigating to previous result:", e); debugLog("Failed to navigate to previous result: " + e.message); } } // Navigate to next result function showNextResult() { try { debugLog(`Navigating to next result from question ${currentResultQuestion + 1}`); if (currentResultQuestion < questions.length - 1) { showResults(currentResultQuestion + 1); } } catch (e) { console.error("Error navigating to next result:", e); debugLog("Failed to navigate to next result: " + e.message); } } // Lazy-load video function loadVideo(button, videoUrl, containerId) { try { debugLog(`Loading video for ${containerId}: ${videoUrl}`); if (!videoUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No video available</p>`; button.remove(); debugLog("No video URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <div class="video-loading"></div> <video controls class="w-full max-w-[600px] rounded-lg" preload="metadata" aria-label="Video explanation"> <source src="${videoUrl}" type="${videoUrl.endsWith('.m3u8') ? 'application/x-mpegURL' : 'video/mp4'}"> Your browser does not support the video tag. </video> `; container.classList.add('active'); button.remove(); // Initialize HLS.js for .m3u8 videos const video = container.querySelector('video'); if (videoUrl.endsWith('.m3u8') && Hls.isSupported()) { const hls = new Hls(); hls.loadSource(videoUrl); hls.attachMedia(video); hls.on(Hls.Events.ERROR, (event, data) => { console.error("HLS.js error:", data); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("HLS.js error: " + JSON.stringify(data)); }); } else if (videoUrl.endsWith('.m3u8') && video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoUrl; } // Handle video load errors video.onerror = () => { console.error("Video load error for URL:", videoUrl); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; debugLog("Video load error for URL: " + videoUrl); }; // Remove loading spinner when video is ready video.onloadedmetadata = () => { container.querySelector('.video-loading').remove(); debugLog("Video loaded successfully"); }; } catch (e) { console.error("Error loading video:", e); debugLog("Failed to load video: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading video. <a href="${videoUrl}" target="_blank" aria-label="Open video in new tab">Open video</a></p>`; } } // Lazy-load audio function loadAudio(button, audioUrl, containerId) { try { debugLog(`Loading audio for ${containerId}: ${audioUrl}`); if (!audioUrl) { const container = document.getElementById(containerId); container.innerHTML = `<p class="text-gray-500">No audio available</p>`; button.remove(); debugLog("No audio URL provided"); return; } const container = document.getElementById(containerId); container.innerHTML = ` <audio controls class="w-full max-w-[600px]" preload="metadata" aria-label="Audio explanation"> <source src="${audioUrl}" type="audio/mpeg"> Your browser does not support the audio tag. </audio> `; container.classList.add('active'); button.remove(); // Handle audio load errors const audio = container.querySelector('audio'); audio.onerror = () => { console.error("Audio load error for URL:", audioUrl); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; debugLog("Audio load error for URL: " + audioUrl); }; debugLog("Audio loaded successfully"); } catch (e) { console.error("Error loading audio:", e); debugLog("Failed to load audio: " + e.message); const container = document.getElementById(containerId); container.innerHTML = `<p class="text-red-500">Error loading audio. <a href="${audioUrl}" target="_blank" aria-label="Open audio in new tab">Open audio</a></p>`; } } // Toggle dark mode function toggleTheme() { try { debugLog("Toggling theme"); document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); debugLog("Theme toggled successfully"); } catch (e) { console.error("Error toggling theme:", e); debugLog("Failed to toggle theme: " + e.message); } } // Load theme preference function loadTheme() { try { debugLog("Loading theme preference"); const theme = localStorage.getItem('theme'); if (theme === 'dark') { document.documentElement.classList.add('dark'); } debugLog("Theme loaded successfully"); } catch (e) { console.error("Error loading theme:", e); debugLog("Failed to load theme: " + e.message); } } // Initialize on DOM content loaded window.addEventListener('DOMContentLoaded', () => { try { debugLog("DOM content loaded, initializing quiz"); loadTheme(); initQuiz(); } catch (e) { console.error("Error during DOMContentLoaded:", e); debugLog("Failed to initialize on DOMContentLoaded: " + e.message); document.getElementById('error-message').innerHTML = "Error initializing quiz. Please check the console for details or contact support."; document.getElementById('error-message').classList.remove('hidden'); } }); </script> </body> </html>" frameborder="0" width="100%" height="2000px">